
######################################################################################
D:\go\go\go标准库示例\archive\tar.go

package main
import (
"archive/tar"
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"time"
)

// 文件类型
const (
TypeReg           = tar.TypeReg           // 普通文件
TypeLink          = tar.TypeLink          // 硬链接
TypeSymlink       = tar.TypeSymlink       // 符号链接
TypeChar          = tar.TypeChar          // 字符节点
TypeBlock         = tar.TypeBlock         // 块节点
TypeDir           = tar.TypeDir           // 目录
TypeFifo          = tar.TypeFifo          // 先进先出队列节点
TypeCont          = tar.TypeCont          // 保留位
TypeXHeader       = tar.TypeXHeader       // 扩展头
TypeXGlobalHeader = tar.TypeXGlobalHeader // 全局扩展头
TypeGNULongName   = tar.TypeGNULongName   // 下一个文件记录有个长名字
TypeGNULongLink   = tar.TypeGNULongLink   // 下一个文件记录指向一个具有长名字的文件
TypeGNUSparse     = tar.TypeGNUSparse     // 稀疏文件
)

const FilePath = "testdata/test.tar"

// 实现了tar格式压缩文件的存取
func main() {
// 写tar文件数据流
buf := write()

// 自动生成并写入文件
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 读tar文件数据流
read(FilePath)
}

func write() bytes.Buffer {
// 声明buffer
var buf bytes.Buffer

// 初始化writer
var tw = tar.NewWriter(&buf)

// 实例化一个结构体切片
var files = []struct {
Name, Body string
}{
{"readme.txt", "This archive contains some text files."},
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
{"todo.txt", "Get animal handling license."},
}

for _, file := range files {
// 根据结构体的内容实例化一个header
hdr := &tar.Header{
Name:       file.Name,             // 记录头域的文件名
Mode:       0600,                  // 权限和模式位
Uid:        0,                     // 所有者的用户ID
Gid:        0,                     // 所有者的组ID
Size:       int64(len(file.Body)), // 字节数（长度）
ModTime:    time.Now(),            // 修改时间
Typeflag:   TypeReg,               // 文件类型
Linkname:   "",                    // 链接的目标名
Uname:      "",                    // 所有者的用户名
Gname:      "",                    // 所有者的组名
Devmajor:   0,                     // 字符设备或块设备的major number
Devminor:   0,                     // 字符设备或块设备的minor number
AccessTime: time.Now(),            // 访问时间
ChangeTime: time.Now(),            // 状态改变时间
}

// writer写入header
if err := tw.WriteHeader(hdr); err != nil {
log.Fatal(err)
}

// writer写入内容
if _, err := tw.Write([]byte(file.Body)); err != nil {
log.Fatal(err)
}
}

// 关闭writer
if err := tw.Close(); err != nil {
log.Fatal(err)
}

return buf
}

func read(path string) {
// 读取文件内容
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

// 实例化buffer
var readBuf = bytes.NewBuffer(bf)

// 初始化一个reader去读取tar内容
tr := tar.NewReader(readBuf)

// 循环读取多个文件内容
for {
// 获取单个文件的header信息
hdr, err := tr.Next()

// 所有文件读取完毕
if err == io.EOF {
break
}

if err != nil {
log.Fatal(err)
}
fmt.Printf("Contents of %s:\n", hdr.Name)

// 读取数据流信息
b, err := ioutil.ReadAll(tr)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", b)
}

}
######################################################################################
D:\go\go\go标准库示例\archive\zip.go

package main

import (
"archive/zip"
"bytes"
"compress/flate"
"fmt"
"io"
"io/ioutil"
"log"
"os"
)

const FilePath = "testdata/test.zip"

// 实现了zip档案文件的读写
func main() {
// 写zip文件数据流
buf := write()

// 自动生成并写入文件
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 读取zip文件数据流
read(FilePath)
}

func write() bytes.Buffer {
// 声明buffer
var buf bytes.Buffer

// 初始化writer
w := zip.NewWriter(&buf)

// 设置压缩级别，不指定则默认
w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
return flate.NewWriter(out, flate.BestCompression)
})

// 实例化一个结构体切片
var files = []struct {
Name, Body string
}{
{"readme.txt", "This archive contains some text files."},
{"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"},
{"todo.txt", "Get animal handling licence.\nWrite more examples."},
}

for _, file := range files {
// 根据文件名称，writer创建文件
f, err := w.Create(file.Name)
if err != nil {
log.Fatal(err)
}

// 创建的文件写入内容
_, err = f.Write([]byte(file.Body))
if err != nil {
log.Fatal(err)
}
}

// 关闭writer.使用defer更舒适
err := w.Close()
if err != nil {
log.Fatal(err)
}

return buf
}

func read(path string) {
// 根据文件路径，获取zip文件内容
r, err := zip.OpenReader(path)
if err != nil {
log.Fatal(err)
}

// 方法最后调用关闭
defer r.Close()

// 循环读取多个文件内容
for _, f := range r.File {
fmt.Printf("Contents of %s:\n", f.Name)

// 打开文件
rc, err := f.Open()
if err != nil {
log.Fatal(err)
}

// 读取文件内容
b, err := ioutil.ReadAll(rc)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", b)

// 关闭文件
rc.Close()
}
}
######################################################################################
D:\go\go\go标准库示例\bufio\bufio.go

package main

import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
)

const FilePath = "a.txt"

// bufio包实现了有缓冲的I/O
func main() {
// 缓冲区写入
buf := write()
fmt.Printf("%s\n", buf.Bytes())

// 写入文件读取测试使用
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 缓冲区读取
read(FilePath)

// 扫描器demo
scannerDemo()

// 扫描器自定义demo
scannerCustomDemo()

// 扫描器切割最后个为空时避免报错的demo
scannerSplitWithCommaDemo()
}

func write() bytes.Buffer {
// 声明buffer
var buf bytes.Buffer

// 初始化writer
var w = bufio.NewWriter(&buf)

// 创建一个自定义长度的缓冲区，必须大于默认值16，小于默认值则以默认值大小生成。
//var w = bufio.NewWriterSize(&buf, 32)
// 写入字符串类型
w.WriteString("Hello, ")

// 写入单个rune类型
w.WriteRune('W')

// 写入单个byte类型
w.WriteByte('o')

// 写入byte类型
w.Write([]byte("rld!"))

// 重置当前缓冲区
w.Flush()

return buf
}



func read(path string) {
var buf bytes.Buffer

// 读取文件内容
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

// 初始化reader
var r = bufio.NewReader(bytes.NewReader(bf))
// 读取内容直到出现 W 停止并输出(丢出缓冲区)，其余内容仍在缓冲区
// r.ReadBytes('W')效果如下
if s, err := r.ReadString('W'); err != nil {
log.Fatal(err)
} else {
fmt.Println(s)
}

// 返回可以从当前缓冲区读取的字节数。
fmt.Println(r.Buffered())

// 将缓冲区内容写入buffer
r.WriteTo(&buf)
fmt.Printf("%s\n", buf.Bytes())
}

func scannerDemo() {
// 声明字符串
input := "foo bar   baz"
// 初始化扫描器模块
scanner := bufio.NewScanner(strings.NewReader(input))

// split调用一个split函数，函数内容可以根据格式自己定义。
// scanwords是一个自带的split函数，用于返回以空格分隔的字符串，删除了周围的空格。它绝不返回空字符串。
scanner.Split(bufio.ScanWords)

// 循环读取
for scanner.Scan() {
//fmt.Printf("%s\n", scanner.Bytes())
fmt.Println(scanner.Text())
}

// 获取异常
if err := scanner.Err(); err != nil {
log.Fatal(err)
}
}



func scannerCustomDemo() {
// An artificial input source.
const input = "1234 5678 1234567901234567890"
scanner := bufio.NewScanner(strings.NewReader(input))
// 自定义split函数
split := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
// 自带的split函数。
advance, token, err = bufio.ScanWords(data, atEOF)
if err == nil && token != nil {
// 字符串转int
_, err = strconv.ParseInt(string(token), 10, 32)
}
return
}
scanner.Split(split)
for scanner.Scan() {
fmt.Printf("%s\n", scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal("Invalid input: ", err)
}
}

func scannerSplitWithCommaDemo() {
const input = "1,2,3,4,"
scanner := bufio.NewScanner(strings.NewReader(input))
onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
for i := 0; i < len(data); i++ {
if data[i] == ',' {

return i + 1, data[:i], nil

}
}

// 最后一个可能是空字符串，error传入ErrFinalToken告诉bufio是最后个，使其不报错。
return 0, data, bufio.ErrFinalToken
}

scanner.Split(onComma)
for scanner.Scan() {
fmt.Printf("%q ", scanner.Text())
}
if err := scanner.Err(); err != nil {
log.Fatal("Invalid input:", err)
}
}
######################################################################################
D:\go\go\go标准库示例\bytes\bytes.go

package main

import (
"bytes"
"fmt"
"unicode"
)

// bytes包实现了操作[]byte的常用函数。本包的函数和strings包的函数相当类似
func main() {
// buffer写入
write()

// buffer直接创建
bufferNew()

// byte操作demo
byteDemo()
}

func write() {
// 声明buffer
var b bytes.Buffer

// 增加buffer容量
b.Grow(64)

// 写入字符串
b.WriteString("Hello ")

// 写入单个byte
b.WriteByte('W')

// 写入单个rune
b.WriteRune('o')

// 写入byte
b.Write([]byte("rld!"))

fmt.Printf("%s\n", b.Bytes())
}

func bufferNew() {
str := "Hello World!"

// 根据字符串创建buffer
buf := bytes.NewBufferString(str)

// 根据byte创建buffer
buf = bytes.NewBuffer([]byte(str))

fmt.Printf("%s\n", buf.Bytes())
}

func byteDemo() {
var a, b, c []byte

// 根据[]byte创建reader
bytes.NewReader([]byte("Hello World!"))

// 比较a和b, 返回 0: a等于b, 1: a包含b, -1: a不包含b
bytes.Compare(a, b)

// 判断a与b是否相同
bytes.Equal(a, b)

// 判断a与b是否相同，忽略大小写
bytes.EqualFold(a, b)

// 判断a是否以b开头，当b为空时true
bytes.HasPrefix(a, b)

// 判断a是否以b结尾，当b为空时true
bytes.HasSuffix(a, b)

// 如果a以b结尾，则返回a去掉b结尾部分的新byte。如果不是，返回a
bytes.TrimSuffix(a, b)

// 如果a以b开头，则返回a去掉b开头部分的新byte。如果不是，返回a
bytes.TrimPrefix(a, b)

// 去除开头结尾所有的 空格换行回车缩进
bytes.TrimSpace(a)

// 去除开头结尾所有的 指定字符串中的任意字符
bytes.Trim(a, " ")

// 按自定义方法 去除开头结尾所有指定内容
bytes.TrimFunc(a, unicode.IsLetter)

// 去除开头所有的 指定字符串中的任意字符
bytes.TrimLeft(a, "0123456789")

// 按自定义方法 去除开头所有指定内容
bytes.TrimLeftFunc(a, unicode.IsLetter)

// 去除结尾所有的 指定字符串中的任意字符
bytes.TrimRight(a, "0123456789")

// 按自定义方法 去除结尾所有指定内容
bytes.TrimRightFunc(a, unicode.IsLetter)

// 以一个或者多个空格分割成切片
bytes.Fields([]byte("  foo bar  baz   "))

// 根据指定方法分割成切片
bytes.FieldsFunc([]byte("  foo1;bar2,baz3..."), func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c) // 以 不是字符或者数字 进行分割
})

// 判断a是否包含b
bytes.Contains(a, b)

// 判断byte是否包含字符串中任意字符，只要包含字符串中一个及以上字符返回true，否则false
bytes.ContainsAny([]byte("I like seafood."), "fÄo!")

// 判断byte是否包含rune字符
bytes.ContainsRune([]byte("I like seafood."), 'f')

// 统计a中包含所有b的个数，如果b为空则返回a的长度
bytes.Count(a, b)

// 检索a中首个b的位置，未检索到返回-1
bytes.Index(a, b)

// 检索a中首个 byte类型字符 的位置，未检索到返回-1
bytes.IndexByte(a, byte('k'))

// 自定义方法检索首个字符的位置，未检索到返回-1
bytes.IndexFunc([]byte("Hello, 世界"), func(c rune) bool {
return unicode.Is(unicode.Han, c) // 是否包含中文字符
})

// 检索a中首个 字符串中任意字符 的位置，未检索到返回-1
bytes.IndexAny(a, "abc")

// 检索a中首个 rune类型字符 的位置，未检索到返回-1
bytes.IndexRune([]byte("chicken"), 'k')

// 检索a中最后个b的位置，未检索到返回-1
bytes.LastIndex(a, b)

// 检索a中最后个 byte类型字符 的位置，未检索到返回-1
bytes.LastIndexByte(a, byte('k'))

// 自定义方法检索最后个字符的位置，未检索到返回-1
bytes.LastIndexFunc(a, unicode.IsLetter)

// 将byte数组以指定 byte字符 连接成一个新的byte
s := [][]byte{a, b}
bytes.Join(s, []byte(","))

// 返回一个重复n次a的新byte
// 例如：a = []byte("abc")，返回 []byte("abcabc")
bytes.Repeat(a, 2)

// 返回一个 将a中的b替换为c 的新byte，n为替换个数，-1替换所有
bytes.Replace(a, b, c, -1)

// 返回一个 将a中的b替换为c 的新byte
bytes.ReplaceAll(a, b, c)

// byte类型转rune类型
bytes.Runes(a)

// 将a以指定字符byte分割成byte数组
bytes.Split(a, []byte(","))

// 将a以指定字符byte分割成byte数组, n为分割个数，-1分割所有
bytes.SplitN(a, []byte(","), 2)

// 将a以指定字符byte分割成byte数组，保留b。
bytes.SplitAfter(a, []byte(","))

// 将a以指定字符byte分割成byte数组，保留b。n为分割个数，-1分割所有
bytes.SplitAfterN(a, []byte(","), 2)

// 返回一个 以空格为界限，所有首个字母大写 的标题格式
bytes.Title(a)

// 返回一个 所有字母大写 的标题格式
bytes.ToTitle(a)

// 使用指定的映射表将 a 中的所有字符修改为标题格式返回。
bytes.ToTitleSpecial(unicode.SpecialCase{}, a)

// 所有字母大写
bytes.ToUpper(a)

// 使用指定的映射表将 a 中的所有字符修改为大写格式返回。
bytes.ToUpperSpecial(unicode.SpecialCase{}, a)

// 所有字母小写
bytes.ToLower(a)

// 使用指定的映射表将 a 中的所有字符修改为大写格式返回。
bytes.ToLowerSpecial(unicode.SpecialCase{}, a)

// 遍历a按指定的rune方法处理每个字符
bytes.Map(func(r rune) rune {
if r >= 'A' && r <= 'Z' {

return r

} else {

return 'a'

}
}, a)
}
######################################################################################
D:\go\go\go标准库示例\compress\compress-bzip2.go

package main

import (
"bytes"
"compress/bzip2"
"fmt"
"io/ioutil"
"log"
)

const FilePath = "testdata/test.bz2"

// bzip2包实现bzip2的解压缩
func main() {
// 读取文件内容
bf, err := ioutil.ReadFile(FilePath)
if err != nil {
log.Fatal(err)
}

// bzip2解压缩成reader
r := bzip2.NewReader(bytes.NewReader(bf))

// 读取内容
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}

fmt.Println("bzip2 content: ", string(b))
}
######################################################################################
D:\go\go\go标准库示例\compress\compress-flate.go

package main

import (
"bytes"
"compress/flate"
"fmt"
"io/ioutil"
"log"
"os"
)

const FilePath = "testdata/test.deflate"
const DictFilePath = "testdata/testDict.deflate"

// flate包实现了deflate压缩数据格式。gzip包和zlib包实现了对基于deflate的文件格式的访问
func main() {
// 写deflate数据流
buf := write()

// 自动生成并写入文件
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 读deflate数据流
read(FilePath)
const dict = `<?xml version="1.0"?><book></book><data></data><meta name="" content="`

// 预设字典写deflate数据流
dictBuf := writeDict(dict)

// 自动生成并写入文件
if err := ioutil.WriteFile(DictFilePath, dictBuf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 根据预设字典读deflate数据流
readDict(dict, DictFilePath)
}

func write() bytes.Buffer {
inputs := []string{
"Don't communicate by sharing memory, share memory by communicating.\n",
"Concurrency is not parallelism.\n",
"The bigger the interface, the weaker the abstraction.\n",
"Documentation is for users.\n",
}

resetInput := "This is a reset test message!"
var buf bytes.Buffer

// 初始化writer，可设置压缩类型
fw, err := flate.NewWriter(&buf, flate.DefaultCompression)
if err != nil {
log.Fatal(err)
}

for _, v := range inputs {
// 写入
if _, err := fw.Write([]byte(v)); err != nil {
log.Fatal(err)
}

// 挂起写入数据，重置缓冲区
if err := fw.Flush(); err != nil {
log.Fatal(err)
}
}



// 重置buffer内容为空
fw.Reset(&buf)
fw.Write([]byte(resetInput))

// 关闭writer
if err := fw.Close(); err != nil {
log.Fatal(err)
}
return buf
}

func read(path string) {
// 读取文件内容
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

// 初始化reader
r := flate.NewReader(bytes.NewReader(bf))
if err := r.Close(); err != nil {
log.Fatal(err)
}

// 读取内容
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}

func writeDict(dict string) bytes.Buffer {
const data = `<?xml version="1.0"?>
<book>
	<meta name="title" content="The Go Programming Language"/>
	<meta name="authors" content="Alan Donovan and Brian Kernighan"/>
	<meta name="published" content="2015-10-26"/>
	<meta name="isbn" content="978-0134190440"/>
	<data>...</data>
</book>`

var buf bytes.Buffer
// 初始化一个预设字典的writer
fw, err := flate.NewWriterDict(&buf, flate.DefaultCompression, []byte(dict))
defer fw.Close()
if err != nil {
log.Fatal(err)
}

// 写入
if _, err := fw.Write([]byte(data)); err != nil {
log.Fatal(err)
}

// 关闭
if err := fw.Close(); err != nil {
log.Fatal(err)
}
return buf
}

func readDict(dict string, path string) {
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

// 可以读取的时候替换字典内容，但是必须保证长度相同，注释测试原字典解压
hashDict := []byte(dict)
for i := range hashDict {
hashDict[i] = '#'
}

// 初始化一个预设字典的reader
fr := flate.NewReaderDict(bytes.NewReader(bf), hashDict)
defer fr.Close()
b, err := ioutil.ReadAll(fr)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
######################################################################################
D:\go\go\go标准库示例\compress\compress-gzip.go

package main

import (
"bytes"
"compress/flate"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"time"
)

const FilePath = "testdata/test.gzip"
// gzip包实现了gzip格式压缩文件的读写

func main() {
// 写gzip数据流
buf := write()

// 自动生成并写入文件
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 读gzip数据流
read(FilePath)
}

func write() bytes.Buffer {
var files = []struct {
name    string
comment string
modTime time.Time
data    string
}{
{"file-1.txt", "file-header-1", time.Now(), "Hello Gophers - 1"},
{"file-2.txt", "file-header-2", time.Now(), "Hello Gophers - 2"},
}

// 声明buffer
var buf bytes.Buffer

// 初始化writer
gw := gzip.NewWriter(&buf)

// 初始化writer，可设置压缩级别
gw, err := gzip.NewWriterLevel(&buf, flate.BestCompression)
if err != nil {
log.Fatal(err)
}

for _, file := range files {
gw.Name = file.name       // 设置文件名称
gw.Comment = file.comment // 设置说明
gw.ModTime = file.modTime // 设置修改时间
gw.Extra = []byte("")     // 设置额外内容

// 写入
if _, err := gw.Write([]byte(file.data)); err != nil {
log.Fatal(err)
}

// 关闭
if err := gw.Close(); err != nil {
log.Fatal(err)
}

// 重置buffer内容
gw.Reset(&buf)
}

return buf
}



func read(path string) {
// 读取文件内容
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

buf := bytes.NewReader(bf)

// 初始化reader
gr, err := gzip.NewReader(buf)
defer gr.Close()
if err != nil {
log.Fatal(err)
}

for {
// 设置数据流文件内容分隔，false分开每个单独文件循环读取reader内容。true所有文件内容一次性读取
gr.Multistream(false)
b, err := ioutil.ReadAll(gr)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Name: %s\nComment: %s\nModTime: %s\n", gr.Name, gr.Comment, gr.ModTime.UTC())
fmt.Println(string(b))

err = gr.Reset(buf)
if err == io.EOF {
break
}
if err != nil {
log.Fatal(err)
}
}
}
######################################################################################
D:\go\go\go标准库示例\compress\compress-lzw.go

package main

import (
"bytes"
"compress/lzw"
"fmt"
"io/ioutil"
"log"
"os"
)

const FilePath = "testdata/test.lzw"
// lzw包实现了Lempel-Ziv-Welch数据压缩格式，这是一种T. A. Welch在“A Technique for High-Performance Data Compression”一文（Computer, 17(6) (June 1984), pp 8-19）提出的一种压缩格式
// 本包实现了用于GIF、TIFF、PDF文件的lzw压缩格式，这是一种最长达到12位的变长码，头两个非字面码为clear和EOF码
func main() {
// 写lzw数据流
buf := write()

// 自动生成并写入文件
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 读lzw数据流
read(FilePath)
}

func write() bytes.Buffer {
var input = "Hello World!"
var buf bytes.Buffer

// lzw: Lempel-Ziv-Welch数据压缩格式
// 初始化writer
// lsb表示最低有效位，在gif文件格式中使用。
// msb表示最高有效位，在tiff和pdf中所用
// litWidth编码位数，范围[2,8]且通常为8。输入字节必须小于1<<litwidth。
lw := lzw.NewWriter(&buf, lzw.LSB, 8)

// 写入
if _, err := lw.Write([]byte(input)); err != nil {
log.Fatal(err)
}

// 关闭
if err := lw.Close(); err != nil {
log.Fatal(err)
}
return buf
}

func read(path string) {
// 读取文件内容
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

// 初始化reader
lr := lzw.NewReader(bytes.NewReader(bf), lzw.LSB, 8)
defer lr.Close()

// 读取内容
b, err := ioutil.ReadAll(lr)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
######################################################################################
D:\go\go\go标准库示例\compress\compress-zlib.go

package main

import (
"bytes"
"compress/zlib"
"fmt"
"io/ioutil"
"log"
"os"
)

const FilePath = "testdata/test.zlib"
// zlib包实现了对zlib格式压缩数据的读写

func main() {
// 写zlib数据流
buf := write()

// 自动生成并写入文件
if err := ioutil.WriteFile(FilePath, buf.Bytes(), os.ModePerm); err != nil {
log.Fatal(err)
}

// 读zlib数据流
read(FilePath)
}

func write() bytes.Buffer {
input := "Hello World!"

// 声明buffer
var buf bytes.Buffer

// 初始化writer
zw := zlib.NewWriter(&buf)

// 写入

if _, err := zw.Write([]byte(input)); err != nil {
log.Fatal(err)
}

// 关闭
if err := zw.Close(); err != nil {
log.Fatal(err)
}
return buf
}

func read(path string) {
// 读取文件内容
bf, err := ioutil.ReadFile(path)
if err != nil {
log.Fatal(err)
}

// 初始化reader
zr, err := zlib.NewReader(bytes.NewReader(bf))
defer zr.Close()
if err != nil {
log.Fatal(err)
}

// 读取内容
b, err := ioutil.ReadAll(zr)
if err != nil {
log.Fatal(err)
}

fmt.Println(string(b))
}
######################################################################################
D:\go\go\go标准库示例\container\heap.go

package main

import "container/heap"

// heap包实现了对任意类型（实现了heap.Interface接口）的堆操作

func main() {
// 初始化结构体
h := &IntHeap{1, 4, 2, 7, 8, 9, 3, 6}

// 初始化堆
heap.Init(h)

// 添加元素并重新排序
heap.Push(h, 5)

// 移除最小元素返回一个新的interface,根据sort排序规则
heap.Pop(h)

// 移除指定位置的interface，返回一个新的interface
heap.Remove(h, 5)

// 移除指定位置的interface，并修复索引
heap.Fix(h, 5)
}

// 声明结构体
type IntHeap []int

// 创建sort.Interface接口的Len方法
func (h IntHeap) Len() int { return len(h) }

// 创建sort.Interface接口的Less方法
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }

// 创建sort.Interface接口的Swap方法
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

// 创建heap.Interface接口的添加方法
func (h *IntHeap) Push(x interface{}) { *h = append(*h, x.(int)) }

// 创建heap.Interface接口的移除方法
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
######################################################################################
D:\go\go\go标准库示例\container\list.go

package main

import (
"container/list"
"fmt"
)

// list包实现双向链表

func main() {
// 初始化链表
l := list.New()
l2 := list.New()

// 向链表后面插入值为v的元素并返回一个新的元素
e4 := l.PushBack(4)

// 向链表后面插入另一个链表,l和l2可以相同，但是都不能为nil
l.PushBackList(l2)

// 向链表前面面插入值为v的元素并返回一个新的元素
e1 := l.PushFront(1)

// 向链表前面插入另一个链表,两个链表可以相同，但是都不能为nil
l.PushFrontList(l2)

// 向元素mark前插入值为v的元素并返回一个新的元素，如果mark不是链表的元素，则不改变链表，mark不能为nil
l.InsertBefore(3, e4)

// 向元素mark后插入值为v的元素并返回一个新的元素，如果mark不是链表的元素，则不改变链表，mark不能为nil
l.InsertAfter(2, e1)

// 如果元素存在链表中，从链表中移除元素，并返回元素值，元素值不能为nil
l.Remove(e1)

// 如果元素存在链表中，将元素移动到链表最前面，元素不能为nil
l.MoveToFront(e4)

// 如果元素存在链表中，将元素移动到链表最后面，元素不能为nil
l.MoveToBack(e1)

// 如果元素e和mark都存在链表中，将e移动到mark前面，两个元素都不能为nil
l.MoveBefore(e1, e4)

// 如果元素e和mark都存在链表中，将e移动到mark后面，两个元素都不能为nil
l.MoveAfter(e1, e4)

// 返回链表长度
l.Len()

// 遍历链表从前面开始打印内容
fmt.Println("front: ")
for e := l.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}

// 遍历链表从后面开始打印内容
fmt.Println("back: ")
for e := l.Back(); e != nil; e = e.Prev() {
fmt.Println(e.Value)
}
}
######################################################################################
D:\go\go\go标准库示例\container\ring.go

package main

import (
"container/ring"
"fmt"
)

// ring包实现环形链表
func main() {
// 初始化n个元素的环形链表
r := ring.New(5)
s := ring.New(5)

// 返回链表长度
n := r.Len()
for i := 0; i < n; i++ {
r.Value = i  // 给元素赋值
r = r.Next() // 获取下一个元素
s.Value = i
s = s.Next()
}

for j := 0; j < n; j++ {
r = r.Prev()         // 获取上一个元素
fmt.Println(r.Value) //
}

// 循环访问环形链表所有元素
r.Do(func(p interface{}) {
fmt.Println(p.(int))
})

// 将前面n个元素移到后面，例：0,1,2,3,4,5 => 3,4,5,0,1,2
r.Move(3)

// 链表r与链表s是不同链表，则在r链表的后面链接s链表，否则删除相同部分
r.Link(s)

// 从下一个元素开始，移除链表连续n个元素
r.Unlink(3)
}
######################################################################################
D:\go\go\go标准库示例\context\context.go

package main

import (
"context"
"time"
)

// Context包定义了上下文类型
func main() {
// 返回一个不是nil的空的Context。当不清楚使用哪个Context或者不可用时（因为功能尚未扩展到接受Context参数）。
context.TODO()

// 返回一个不是nil的空Context。它永远不会被取消，没有值，也没有存活时间。 它通常由主函数，初始化和测试使用，并作为传入请求的顶级Context。
ctx := context.Background()

// 根据Context，返回一个Context副本和一个取消方法，以方便完成工作后释放资源
_, cancel := context.WithCancel(ctx)
defer cancel()

// 根据Context和最迟存活时间，返回一个Context副本和一个取消方法，以方便完成工作后释放资源
context.WithDeadline(ctx, time.Now().Add(50 * time.Millisecond))

// 根据Context和超时时间，返回一个Context副本和一个取消方法，以方便完成工作后释放资源
context.WithTimeout(ctx, time.Millisecond * 50)

// 给Context添加自定义类型的键值对，返回一个新的Context
context.WithValue(ctx, "language", "Go")
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-aes.go


package main

import (
"crypto/rand"
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/zc2638/go-standard/src/crypto/aes/extra"
"io"
"log"
)



// 实现AES加密算法
func main() {
// AES-CBC加密/解密
CBC()

// AES-GCM加密/解密
GCM()

// AES-CFB加密/解密
CFB()

// AES-CTR加密/解密
CTR()

// AES-OFB加密/解密
OFB()

// AES-OFB加密/解密，使用cipher的StreamReader加密、cipher的StreamWriter解密
OFBStream()
}



func CBC() {
// 声明一个16字节的key
var key = []byte("example key 1234")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to aes-cbc encode test text")

// 声明一个16字节的iv
var iv = []byte("example iv tests")

// 加密
cipherText, err := extra.CBCEncrypt(origin, key, iv)
if err != nil {
log.Fatal(err)
}

// byte转base64字符串
cipherTextStr := base64.StdEncoding.EncodeToString(cipherText)
fmt.Println("AES-CBC加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CBCDecrypt(cipherText, key, iv)
if err != nil {
log.Fatal(err)
}
fmt.Println("AES-CBC解密内容: ", string(originText))
}

func GCM() {
// 声明一个16字节的key
var key = []byte("0123456789ABCDEF")
// 声明一个随意长度的 需加密内容
var origin = []byte("need to aes-gcm encode test text")

// 初始化一个长度为12字节的空的[]byte，不要使用超过2^32个随机非字符，因为存在重复的风险
nonce := make([]byte, 12)

// 使用rand随机生成数据
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
log.Fatal(err)
}

// 加密
cipherText, err := extra.GCMEncrypt(origin, key, nonce)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("AES-GCM加密内容: ", cipherTextStr)

// 解密
originText, err := extra.GCMDecrypt(cipherText, key, nonce)
if err != nil {
log.Fatal(err)
}
fmt.Println("AES-GCM解密内容: ", string(originText))
}

func CFB() {

// 声明一个16字节的key
var key = []byte("0123456789ABCDEF")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to aes-cfb encode test text")

// 声明一个16字节的iv
var iv = []byte("example iv tests")

// 加密
cipherText, err := extra.CFBEncrypt(origin, key, iv)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("AES-CFB加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CFBDecrypt(cipherText, key, iv)
if err != nil {
log.Fatal(err)
}
fmt.Println("AES-CFB解密内容: ", string(originText))
}

func CTR() {
// 声明一个16字节的key
var key = []byte("0123456789ABCDEF")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to aes-ctr encode test text")

// 声明一个16字节的iv
var iv = []byte("example iv tests")

// 加密
cipherText, err := extra.CTREncrypt(origin, key, iv)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("AES-CTR加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CTRDecrypt(cipherText, key, iv)
if err != nil {
log.Fatal(err)
}
fmt.Println("AES-CTR解密内容: ", string(originText))
}

func OFB() {
// 声明一个16字节的key
var key = []byte("0123456789ABCDEF")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to aes-ofb encode test text")

// 声明一个16字节的iv
var iv = []byte("example iv tests")

// 加密
cipherText, err := extra.OFBEncrypt(origin, key, iv)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("AES-OFB加密内容: ", cipherTextStr)

// 解密
originText, err := extra.OFBDecrypt(cipherText, key, iv)
if err != nil {
log.Fatal(err)
}
fmt.Println("AES-OFB解密内容: ", string(originText))
}

func OFBStream() {
// 声明一个16字节的key
var key = []byte("0123456789ABCDEF")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to aes-ofb-stream encode test text")

// 声明一个16字节的iv
var iv = []byte("example iv tests")

// StreamReader方式加密
cipherText, err := extra.OFBEncryptStreamReader(origin, key, iv)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("AES-OFB-Stream方式加密内容: ", cipherTextStr)

// StreamWriter方式解密
originText, err := extra.OFBDecryptStreamWriter(cipherText, key, iv)
if err != nil {
log.Fatal(err)
}
fmt.Println("AES-OFB-Stream方式解密内容: ", string(originText))
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-cipher.go


package main

// 实现了多个标准的用于包装底层块加密算法的加密算法实现

func main() {

// 详细example请查看crypto/aes下的example
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-des-extra-cbc.go

package extra

import (
"bytes"
"crypto/cipher"
"crypto/des"
)

func CBCEncrypt(originText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 返回加密字节块的大小
blockSize := block.BlockSize()

// PKCS5填充需加密内容
originText = PKCS5Padding(originText, blockSize)

// 返回一个密码分组链接模式的、底层用Block加密的cipher.BlockMode，初始向量iv的长度必须等于Block的块尺寸(Block块尺寸等于密钥尺寸)
blockMode := cipher.NewCBCEncrypter(block, iv)

// 根据 需加密内容[]byte长度,初始化一个新的byte数组，返回byte数组内存地址
cipherText := make([]byte, len(originText))

// 加密或解密连续的数据块，将加密内容存储到dst中，src需加密内容的长度必须是块大小的整数倍，src和dst可指向同一内存地址
blockMode.CryptBlocks(cipherText, originText)

return cipherText, nil
}

func CBCDecrypt(cipherText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 返回一个密码分组链接模式的、底层用b解密的cipher.BlockMode，初始向量iv必须和加密时使用的iv相同
blockMode := cipher.NewCBCDecrypter(block, iv)

// 根据 密文[]byte长度,初始化一个新的byte数组，返回byte数组内存地址
originText := make([]byte, len(cipherText))

// 加密或解密连续的数据块，将解密内容存储到dst中，src需加密内容的长度必须是块大小的整数倍，src和dst可指向同一内存地址
blockMode.CryptBlocks(originText, cipherText)

// PKCS5反填充解密内容
originText = PKCS5UnPadding(originText)
return originText, nil
}

func PKCS5Padding(cipherText []byte, blockSize int) []byte {
// 获取 需加密字符串长度 和 加密字节块长度 的余数
less := len(cipherText) % blockSize

// 求填充长度
padding := blockSize - less

// 将填充长度 重复 长度padding次，返回填充内容
padText := bytes.Repeat([]byte{byte(padding)}, padding)

// 将填充内容 添加到 需加密内容
return append(cipherText, padText...)
}

func PKCS5UnPadding(originText []byte) []byte {
// 获取 解密内容长度
length := len(originText)

// 获取反填充长度(只获取最后个byte当做长度，因为填充的时候是重复按照长度填充的)
unPadding := int(originText[length-1])

// 截取解密内容中的原文内容
return originText[:(length - unPadding)]
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-des-extra-cfb.go

package extra

import (
"crypto/aes"
"crypto/cipher"
"crypto/des"
"errors"
)

func CFBEncrypt(originText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 根据 需加密内容[]byte长度,初始化一个新的byte数组，返回byte数组内存地址
cipherText := make([]byte, aes.BlockSize+len(originText))

// 返回一个密码反馈模式的、底层用block加密的cipher.Stream，初始向量iv的长度必须等于block的块尺寸
stream := cipher.NewCFBEncrypter(block, iv)

// 从加密器的key流和src中依次取出字节二者xor后写入dst，src和dst可指向同一内存地址
// cipherText[:aes.BlockSize]为iv值，所以只写入cipherText后面部分
stream.XORKeyStream(cipherText[aes.BlockSize:], originText)
return cipherText, nil
}

func CFBDecrypt(cipherText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}
if len(cipherText) < aes.BlockSize {

return nil, errors.New("cipherText too short")

}

// 只使用cipherText除去iv部分
cipherText = cipherText[aes.BlockSize:]

// 返回一个密码反馈模式的、底层用block解密的cipher.Stream，初始向量iv必须和加密时使用的iv相同
stream := cipher.NewCFBDecrypter(block, iv)

// 从加密器的key流和src中依次取出字节二者xor后写入dst，src和dst可指向同一内存地址
stream.XORKeyStream(cipherText, cipherText)
return cipherText, nil
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-des-extra-ctr.go

package extra

import (
"crypto/aes"
"crypto/cipher"
"crypto/des"
)

func CTREncrypt(originText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 根据 需加密内容[]byte长度,初始化一个新的byte数组，返回byte数组内存地址
cipherText := make([]byte, aes.BlockSize+len(originText))

// 返回一个计数器模式的、底层采用block生成key流的cipher.Stream，初始向量iv的长度必须等于block的块尺寸
stream := cipher.NewCTR(block, iv)

// 从加密器的key流和src中依次取出字节二者xor后写入dst，src和dst可指向同一内存地址
// cipherText[:aes.BlockSize]为iv值，所以只写入cipherText后面部分
stream.XORKeyStream(cipherText[aes.BlockSize:], originText)

return cipherText, nil
}

func CTRDecrypt(cipherText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 只使用cipherText除去iv部分
cipherText = cipherText[aes.BlockSize:]

// 返回一个计数器模式的、底层采用block生成key流的cipher.Stream，初始向量iv的长度必须等于block的块尺寸
stream := cipher.NewCTR(block, iv)

// 从加密器的key流和src中依次取出字节二者xor后写入dst，src和dst可指向同一内存地址
stream.XORKeyStream(cipherText, cipherText)
return cipherText, nil
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-des-extra-ofb.go

package extra

import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/des"
"io"
"io/ioutil"
"log"
)

func OFBEncrypt(originText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 根据 需加密内容[]byte长度,初始化一个新的byte数组，返回byte数组内存地址
cipherText := make([]byte, aes.BlockSize+len(originText))

// 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream，初始向量iv的长度必须等于b的块尺寸
stream := cipher.NewOFB(block, iv)

// 从加密器的key流和src中依次取出字节二者xor后写入dst，src和dst可指向同一内存地址
// cipherText[:aes.BlockSize]为iv值，所以只写入cipherText后面部分
stream.XORKeyStream(cipherText[aes.BlockSize:], originText)

return cipherText, nil
}

func OFBDecrypt(cipherText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 只使用cipherText除去iv部分
cipherText = cipherText[aes.BlockSize:]

// 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream，初始向量iv的长度必须等于b的块尺寸
stream := cipher.NewOFB(block, iv)

// 从加密器的key流和src中依次取出字节二者xor后写入dst，src和dst可指向同一内存地址
stream.XORKeyStream(cipherText, cipherText)

return cipherText, nil
}

func OFBEncryptStreamReader(originText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream，初始向量iv的长度必须等于b的块尺寸
stream := cipher.NewOFB(block, iv)

// 初始化cipher.StreamReader。将一个cipher.Stream与一个io.Reader关联起来，Read方法会调用XORKeyStream方法来处理获取的所有切片
reader := &cipher.StreamReader{
S: stream,
R: bytes.NewReader(originText),
}

return ioutil.ReadAll(reader)
}

func OFBDecryptStreamWriter(cipherText, key, iv []byte, triple bool) ([]byte, error) {
var block cipher.Block
var err error
if triple {
// 创建一个cipher.Block。参数key为24字节密钥
block, err = des.NewTripleDESCipher(key)
} else {
// 创建一个cipher.Block。参数key为8字节密钥
block, err = des.NewCipher(key)
}
if err != nil {

return nil, err

}

// 返回一个输出反馈模式的、底层采用b生成key流的cipher.Stream，初始向量iv的长度必须等于b的块尺寸
stream := cipher.NewOFB(block, iv)

// 声明buffer
var originText bytes.Buffer

// 初始化cipher.StreamWriter。将一个cipher.Stream与一个io.Writer接口关联起来，Write方法会调用XORKeyStream方法来处理提供的所有切片
// 如果Write方法返回的n小于提供的切片的长度，则表示StreamWriter不同步，必须丢弃。StreamWriter没有内建的缓存，不需要调用Close方法去清空缓存
writer := &cipher.StreamWriter{
S: stream,
W: &originText,
}

// 把reader内容拷贝到writer, writer会调用write方法写入内容
if _, err := io.Copy(writer, bytes.NewReader(cipherText)); err != nil {
log.Fatal(err)
}
return originText.Bytes(), nil
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-des.go

package main

import (
"encoding/base64"
"encoding/hex"
"fmt"
"github.com/zc2638/go-standard/src/crypto/des/extra"
"log"
)

// 实现了DES标准和TDEA算法
func main() {
// DES-CBC加密/解密
CBC()

// DES-CFB加密/解密
CFB()

// DES-CTR加密/解密
CTR()

// DES-OFB加密/解密
OFB()

// DES-OFB加密/解密，使用cipher的StreamReader加密、cipher的StreamWriter解密
OFBStream()

CBCTriple()

CFBTriple()

CTRTriple()

OFBTriple()

OFBStreamTriple()
}

func CBC() {
// 声明一个8字节的key
var key = []byte("test key")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-cbc encode test text")

// 声明一个8字节的iv
var iv = []byte("test ivs")

// 加密
cipherText, err := extra.CBCEncrypt(origin, key, iv, false)
if err != nil {
log.Fatal(err)
}

// byte转base64字符串
cipherTextStr := base64.StdEncoding.EncodeToString(cipherText)
fmt.Println("DES-CBC加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CBCDecrypt(cipherText, key, iv, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-CBC解密内容: ", string(originText))
}

func CFB() {
// 声明一个8字节的key
var key = []byte("12345678")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-cfb encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// 加密
cipherText, err := extra.CFBEncrypt(origin, key, iv, false)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-CFB加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CFBDecrypt(cipherText, key, iv, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-CFB解密内容: ", string(originText))
}

func CTR() {
// 声明一个8字节的key
var key = []byte("12345678")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-ctr encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// 加密
cipherText, err := extra.CTREncrypt(origin, key, iv, false)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-CTR加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CTRDecrypt(cipherText, key, iv, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-CTR解密内容: ", string(originText))
}

func OFB() {
// 声明一个8字节的key
var key = []byte("12345678")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-ofb encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// 加密
cipherText, err := extra.OFBEncrypt(origin, key, iv, false)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-OFB加密内容: ", cipherTextStr)

// 解密
originText, err := extra.OFBDecrypt(cipherText, key, iv, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-OFB解密内容: ", string(originText))
}

func OFBStream() {
// 声明一个8字节的key
var key = []byte("12345678")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-ofb-stream encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// StreamReader方式加密
cipherText, err := extra.OFBEncryptStreamReader(origin, key, iv, false)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-OFB-Stream方式加密内容: ", cipherTextStr)

// StreamWriter方式解密
originText, err := extra.OFBDecryptStreamWriter(cipherText, key, iv, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-OFB-Stream方式解密内容: ", string(originText))
}



func CBCTriple() {
// 声明一个24字节的key
var key = []byte("it is 24 bytes test key!")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-cbc-triple encode test text")

// 声明一个8字节的iv
var iv = []byte("test ivs")

// 加密
cipherText, err := extra.CBCEncrypt(origin, key, iv, true)
if err != nil {
log.Fatal(err)
}

// byte转base64字符串
cipherTextStr := base64.StdEncoding.EncodeToString(cipherText)
fmt.Println("DES-CBC-Triple加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CBCDecrypt(cipherText, key, iv, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-CBC-Triple解密内容: ", string(originText))
}

func CFBTriple() {
// 声明一个24字节的key
var key = []byte("it is 24 bytes test key!")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-cfb-triple encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// 加密
cipherText, err := extra.CFBEncrypt(origin, key, iv, true)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-CFB-Triple加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CFBDecrypt(cipherText, key, iv, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-CFB-Triple解密内容: ", string(originText))
}

func CTRTriple() {
// 声明一个24字节的key
var key = []byte("it is 24 bytes test key!")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-ctr-triple encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// 加密
cipherText, err := extra.CTREncrypt(origin, key, iv, true)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-CTR-Triple加密内容: ", cipherTextStr)

// 解密
originText, err := extra.CTRDecrypt(cipherText, key, iv, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-CTR-Triple解密内容: ", string(originText))
}

func OFBTriple() {
// 声明一个24字节的key
var key = []byte("it is 24 bytes test key!")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-ofb-triple encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// 加密
cipherText, err := extra.OFBEncrypt(origin, key, iv, true)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-OFB-Triple加密内容: ", cipherTextStr)

// 解密
originText, err := extra.OFBDecrypt(cipherText, key, iv, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-OFB-Triple解密内容: ", string(originText))
}

func OFBStreamTriple() {
// 声明一个24字节的key
var key = []byte("it is 24 bytes test key!")

// 声明一个随意长度的 需加密内容
var origin = []byte("need to des-ofb-triple-stream encode test text")

// 声明一个8字节的iv
var iv = []byte("iv tests")

// StreamReader方式加密
cipherText, err := extra.OFBEncryptStreamReader(origin, key, iv, true)
if err != nil {
log.Fatal(err)
}

// byte转十六进制字符串
cipherTextStr := hex.EncodeToString(cipherText)
fmt.Println("DES-OFB-Triple-Stream方式加密内容: ", cipherTextStr)

// StreamWriter方式解密
originText, err := extra.OFBDecryptStreamWriter(cipherText, key, iv, true)
if err != nil {
log.Fatal(err)
}
fmt.Println("DES-OFB-Triple-Stream方式解密内容: ", string(originText))
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-dsa.go

package main
import (
"crypto/dsa"
"crypto/rand"
"fmt"
"log"
"math/big"
)

// 实现FIPS 186-3定义的数字签名算法(DSA算法)
func main() {
// 声明一个DSA参数中的质数可以接受的字位长度的枚举
var size = dsa.L1024N160

// 声明新的dsa.PrivateKey
var pri dsa.PrivateKey

// 获取密钥域的参数的地址
params := &pri.Parameters

// 随机设置合法的参数到params。即使机器很快，函数也可能会花费很多时间来生成参数
err := dsa.GenerateParameters(params, rand.Reader, size)
if err != nil {
log.Fatal(err)
}

if params.P.BitLen() != 1024 {
log.Fatalf("%d: params.BitLen got:%d want:%d\n", int(size), params.P.BitLen(), 1024)
}

if params.Q.BitLen() != 160 {
log.Fatalf("%d: q.BitLen got:%d want:%d\n", int(size), params.Q.BitLen(), 160)
}

// 声明一个高精度的数值
one := new(big.Int).SetInt64(1)

// 声明一个params.P减去one值的高精度数值
pm1 := new(big.Int).Sub(params.P, one)

// 如果y != 0将z设为x/y，将m设为 x%y 并返回(z, m)；如果y == 0会panic
quo, rem := new(big.Int).DivMod(pm1, params.Q, new(big.Int))
if rem.Sign() != 0 {
log.Fatalf("%d: p-1 mod q != 0\n", int(size))
}

// 将z设为x**y mod |m|并返回z；如果y <= 0，返回1；如果m == nil 或 m == 0，z设为x**y
x := new(big.Int).Exp(params.G, quo, params.P)
if x.Cmp(one) == 0 {
log.Fatalf("%d: invalid generator\n", int(size))
}

// 生成一对公私钥
err = dsa.GenerateKey(&pri, rand.Reader)
if err != nil {
log.Fatalf("error generating key: %s\n", err)
}

// 声明签名内容
var origin = []byte("Hello World!")

// 使用私钥对任意长度的hash值（必须是较大信息的hash结果）进行签名，返回签名结果（一对大整数）
r, s, err := dsa.Sign(rand.Reader, &pri, origin)
if err != nil {
log.Fatalf("%d: error signing: %s\n", int(size), err)
}
fmt.Println("DSA签名内容:", r, s)

// 使用公钥验证hash值和两个大整数r、s构成的签名，并返回签名是否合法
if !dsa.Verify(&pri.PublicKey, origin, r, s) {
log.Fatalf("%d: Verify failed\n", int(size))
}
fmt.Println("DSA签名验证成功")
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-ecdsa.go

package main

import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"fmt"
"log"
)

// 实现了椭圆曲线数字签名算法
func main() {
// 生成一对公钥/私钥
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}

// 声明签名内容
msg := "hello, world"

// 返回数据的SHA256校验和
hash := sha256.Sum256([]byte(msg))

// 使用私钥对任意长度的hash值（必须是较大信息的hash结果）进行签名，返回签名结果（一对大整数）。私钥的安全性取决于密码读取器的熵度（随机程度）
r, s, err := ecdsa.Sign(rand.Reader, privateKey, hash[:])
if err != nil {
log.Fatal(err)
}
fmt.Printf("signature: (0x%x, 0x%x)\n", r, s)

// 使用公钥验证hash值和两个大整数r、s构成的签名，并返回签名是否合法
valid := ecdsa.Verify(&privateKey.PublicKey, hash[:], r, s)
fmt.Println("signature verified:", valid)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-elliptic.go

package main

import (
"crypto/elliptic"
"crypto/rand"
"encoding/hex"
"fmt"
"log"
)

// 实现了几条覆盖素数有限域的标准椭圆曲线
func main() {
// 返回一个实现了P-224的曲线
elliptic.P224()

// 返回一个实现了P-256的曲线
elliptic.P256()

// 返回一个实现了P-384的曲线
elliptic.P384()

// 返回一个实现了P-521的曲线
curve := elliptic.P521()

// 返回一个公钥/私钥对。priv是私钥，而(x,y)是公钥。密钥对是通过提供的随机数读取器来生成的，该io.Reader接口必须返回随机数据
priv, x, y, err := elliptic.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
log.Fatal(err)
}
fmt.Println(hex.EncodeToString(priv))
fmt.Println(x)
fmt.Println(y)

// 将一个点编码为ANSI X9.62指定的格式
d := elliptic.Marshal(curve, x, y)

// 将一个Marshal编码后的点还原；如果出错，x会被设为nil
elliptic.Unmarshal(curve, d)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-hmac.go

package main
import (
"crypto/hmac"
"crypto/sha256"
)

// 实现了U.S. Federal Information Processing Standards Publication 198规定的HMAC（加密哈希信息认证码）
func main() {
// 声明密钥
var key = []byte("test hmac key")

// 声明随意内容
var content = []byte("Hello World!")

// 返回一个采用hash.Hash作为底层hash接口、key作为密钥的HMAC算法的hash接口
h := hmac.New(sha256.New, key)

// 写入
h.Write(content)

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
expectedMAC := h.Sum(nil)

// 比较两个MAC是否相同
hmac.Equal(expectedMAC, expectedMAC)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-md5.go

package main
import (
"crypto"
"crypto/md5"
"encoding/base64"
"fmt"
)

// 实现了MD5哈希算法
func main() {
// 返回一个新的使用MD5校验的hash.Hash
h := md5.New()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.MD5
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用md5.Sum
m3 := md5.Sum([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-rand.go

package main

import (
"crypto/rand"
"fmt"
"log"
"math/big"
)

// 实现了用于加解密的更安全的随机数生成器
func main() {
// 声明一个指定长度的byte切片地址
b := make([]byte, 10)

// 随机填充b。本函数是一个使用io.ReadFull调用Reader.Read的辅助性函数。当且仅当err == nil时，返回值n == len(b)
if _, err := rand.Read(b); err != nil {
log.Fatal(err)
}

// 返回一个统一的随机值，最大不会超过设置的max值，设置的max值必须大于0
// rand.Reader是一个全局、共享的密码用强随机生成器
i, err := rand.Int(rand.Reader, big.NewInt(10))
if err != nil {
log.Fatal(err)
}
fmt.Println(i.Bytes())

// 返回一个具有指定字位数的数字，该数字具有很高可能性是质数。如果从rand读取时出错，或者bits<2会返回错误
p, err := rand.Prime(rand.Reader, 11)
if err != nil {
log.Fatal(err)
}
fmt.Println(p.Bytes())
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-rc4.go

package main

import (
"crypto/rc4"
"encoding/hex"
"fmt"
"log"
)

// 实现了RC4加密算法
func main() {
// 声明密钥
var key = []byte("example key")

// 声明内容
var text = []byte("Hello World!")

// 创建并返回一个新的Cipher。参数key是RC4密钥
c, err := rc4.NewCipher(key)
if err != nil {
log.Fatal(err)
}

// 加密。将src的数据与秘钥生成的伪随机位流取XOR并写入dst。dst和src可指向同一内存地址；但如果指向不同则其底层内存不可重叠
c.XORKeyStream(text, text)

// byte转十六进制字符串
textStr := hex.EncodeToString(text)
fmt.Println(textStr)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-rsa-extra-oaep.go

package extra

import (
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/pem"
"errors"
"log"
)

func EncryptOAEP(publicKey, originText, label []byte) ([]byte, error) {
// 获取rsa.PublicKey
pub, err := BuildRSAPublicKey(publicKey)
if err != nil {
log.Fatal(err)
}

// 采用RSA-OAEP算法加密指定数据。数据不能超过((公共模数的长度)-2*( hash长度)+2)字节
// label参数可能包含不加密的任意数据，但这给了信息重要的背景。例如，如果给定公钥用于解密两种类型的消息，然后是不同的标签值可用于确保用于一个目的的密文不能 被攻击者用于另一个目的。如果不需要，可以为空
return rsa.EncryptOAEP(sha256.New(), rand.Reader, pub, originText, label)
}

func DecryptOAEP(privateKey, cipherText, label []byte) ([]byte, error) {
// 获取rsa.PrivateKey
pri, err := BuildRSAPrivateKey(privateKey)
if err != nil {
log.Fatal(err)
}

// 使用PKCS#1 v1.5规定的填充方案和RSA算法解密密文。如果random不是nil，函数会注意规避时间侧信道攻击
return rsa.DecryptOAEP(sha256.New(), rand.Reader, pri, cipherText, label)
}

func BuildRSAPublicKey(publicKey []byte) (*rsa.PublicKey, error) {
// 返回解码得到的pem.Block和剩余未解码的数据。如果未发现PEM数据，返回(nil, data)
block, _ := pem.Decode(publicKey)
if block == nil {

return nil, errors.New("public key error")

}

// 解析一个DER编码的公钥。这些公钥一般在以"BEGIN PUBLIC KEY"出现的PEM块中
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {

return nil, err

}

// 指定为rsa.PublicKey结构
pub := pubInterface.(*rsa.PublicKey)
return pub, nil
}

func BuildRSAPrivateKey(privateKey []byte) (*rsa.PrivateKey, error) {
// 返回解码得到的pem.Block和剩余未解码的数据。如果未发现PEM数据，返回(nil, data)
block, _ := pem.Decode(privateKey)
if block == nil {

return nil, errors.New("private key error")

}

// 解析一个未加密的PKCS#8私钥
priInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {

return nil, err

}

// 指定为rsa.PrivateKey结构
pri := priInterface.(*rsa.PrivateKey)
return pri, nil
}

func BuildRSAPKCS1PublicKey(publicKey []byte) (*rsa.PublicKey, error) {
// 返回解码得到的pem.Block和剩余未解码的数据。如果未发现PEM数据，返回(nil, data)
block, _ := pem.Decode(publicKey)
if block == nil {

return nil, errors.New("public key error")

}

// 解析一个ASN.1 PKCS#1 DER编码的公钥。
return x509.ParsePKCS1PublicKey(block.Bytes)
}

func BuildRSAPKCS1PrivateKey(privateKey []byte) (*rsa.PrivateKey, error) {
// 返回解码得到的pem.Block和剩余未解码的数据。如果未发现PEM数据，返回(nil, data)
block, _ := pem.Decode(privateKey)
if block == nil {

return nil, errors.New("private key error")

}

// 解析一个ASN.1 PKCS#1 DER编码的私钥。
return x509.ParsePKCS1PrivateKey(block.Bytes)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-rsa-extra-pass.go

package extra
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"log"
)
func SignPass(privateKey, originText []byte, opts *rsa.PSSOptions) ([]byte, error) {
// 获取rsa.PrivateKey
pri, err := BuildRSAPrivateKey(privateKey)
if err != nil {
log.Fatal(err)
}

// 声明MD5 Hash类型
hash := crypto.MD5

// 根据Hash类型创建hash
h := hash.New()

// 写入内容
h.Write(originText)

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
hashed := h.Sum(nil)

// 采用RSASSA-PSS方案计算签名
// 注意hashed必须是使用提供给本函数的hash参数对（要签名的）原始数据进行hash的结果
// opts参数可以为nil，此时会使用默认参数
return rsa.SignPSS(rand.Reader, pri, hash, hashed, opts)
}

func VerifyPass(publicKey, originText, signature []byte, opts *rsa.PSSOptions) error {
// 获取rsa.PublicKey
pub, err := BuildRSAPublicKey(publicKey)
if err != nil {
log.Fatal(err)
}

// 声明MD5 Hash类型
hash := crypto.MD5

// 根据Hash类型创建hash
h := hash.New()

// 写入内容
h.Write(originText)

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
hashed := h.Sum(nil)

// 认证一个PSS签名
// hashed是使用提供给本函数的hash参数对（要签名的）原始数据进行hash的结果。合法的签名会返回nil，否则表示签名不合法
// opts参数可以为nil，此时会使用默认参数
return rsa.VerifyPSS(pub, hash, hashed, signature, opts)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-rsa-extra-pkcs1v15.go

package extra
import (
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"log"
)

func Encrypt(publicKey, originText []byte) ([]byte, error) {
// 获取rsa.PublicKey
pub, err := BuildRSAPublicKey(publicKey)
if err != nil {
log.Fatal(err)
}

// 使用PKCS#1 v1.5规定的填充方案和RSA算法加密msg。信息不能超过((公共模数的长度)-11)字节
// 注意：使用本函数加密明文（而不是会话密钥）是危险的，请尽量在新协议中使用RSA OAEP
return rsa.EncryptPKCS1v15(rand.Reader, pub, originText)
}

func Decrypt(privateKey, cipherText []byte) ([]byte, error) {
// 获取rsa.PrivateKey
pri, err := BuildRSAPrivateKey(privateKey)
if err != nil {

return nil, err

}

// 使用PKCS#1 v1.5规定的填充方案和RSA算法解密密文。如果random不是nil，函数会注意规避时间侧信道攻击
return rsa.DecryptPKCS1v15(rand.Reader, pri, cipherText)
}

func Sign(privateKey, originText []byte) ([]byte, error) {
// 获取rsa.PrivateKey
pri, err := BuildRSAPrivateKey(privateKey)
if err != nil {
log.Fatal(err)
}

// 返回数据的 SHA256 校验和
hashed := sha256.Sum256(originText)

// 使用RSA PKCS#1 v1.5规定的RSASSA-PKCS1-V1_5-SIGN签名方案计算签名
// 注意hashed必须是使用提供给本函数的hash参数对（要签名的）原始数据进行hash的结果
return rsa.SignPKCS1v15(rand.Reader, pri, crypto.SHA256, hashed[:])
}

func Verify(publicKey, originText, signature []byte) error {
// 获取rsa.PublicKey
pub, err := BuildRSAPublicKey(publicKey)
if err != nil {
log.Fatal(err)
}

// 返回数据的 SHA256 校验和
hashed := sha256.Sum256(originText)

// 验证 RSA PKCS＃1 v1.5 签名
// hashed是使用提供的hash参数对（要签名的）原始数据进行hash的结果。合法的签名会返回nil，否则表示签名不合法
return rsa.VerifyPKCS1v15(pub, crypto.SHA256, hashed[:], signature)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-rsa.go

package main

import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"github.com/zc2638/go-standard/src/crypto/rsa/extra"
"io/ioutil"
"log"
"os"
)

const (
PublicPemFile = "testdata/rsa_public.pem"
PublicPKCS1PemFile = "testdata/rsa_public_pkcs1.pem"
PrivatePemFile = "testdata/rsa_private.pem"
PrivatePKCS1PemFile = "testdata/rsa_private_pkcs1.pem"
)

// 实现了PKCS#1规定的RSA加密算法
func main() {
// 生成RSA密钥对
generateRSAKey()

// 使用PKCS#1v1.5规定的填充方案和RSA公钥加密/私钥解密
rsaPKCS1v15Demo()

// RSA-OAEP算法公钥加密/私钥解密
rsaOAEPDemo()

// RSA私钥签名/公钥验证
rsaSignatureDemo()

// RSA-PASS私钥签名/公钥验证
rsaSignPassDemo()
}

func generateRSAKey() {
// 声明位数
var bits = 1024

// 使用随机数据生成器random生成一对具有指定位数的RSA密钥
privateKey, err := rsa.GenerateKey(rand.Reader, bits)

// 使用指定的位数生成一对多质数的RSA密钥。(质数定义为在大于1的自然数中，除了1和它本身以外不再有其他因数)
// 虽然公钥可以和二质数情况下的公钥兼容（事实上，不能区分两种公钥），私钥却不行。
// 因此有可能无法生成特定格式的多质数的密钥对，或不能将生成的密钥用在其他（语言的）代码里
//privateKey, err := rsa.GenerateMultiPrimeKey(rand.Reader, 5, bits)
if err != nil {
log.Fatal(err)
}

// 将rsa私钥序列化为ASN.1 PKCS#1 DER编码
derPrivate := x509.MarshalPKCS1PrivateKey(privateKey)

// 初始化一个PEM编码的结构
priBlock := &pem.Block{
Type:  "PRIVATE KEY",
Bytes: derPrivate,
}

// 创建文件，如果文件存在内容重置为空
file, err := os.Create(PrivatePKCS1PemFile)
defer file.Close()
if err != nil {
log.Fatal(err)
}

// 将Block的pem编码写入文件
err = pem.Encode(file, priBlock)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA-PKCS1私钥生成成功")

// 将rsa私钥序列化为PKCS#8 DER编码
derPrivate8, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
log.Fatal(err)
}

// 初始化一个PEM编码的结构
priBlock8 := &pem.Block{
Type:  "PRIVATE KEY",
Bytes: derPrivate8,
}

// 创建文件，如果文件存在内容重置为空
file2, err := os.Create(PrivatePemFile)
defer file2.Close()
if err != nil {
log.Fatal(err)
}

// 将Block的pem编码写入文件
err = pem.Encode(file2, priBlock8)
if err != nil {
log.Fatal(err)
}

fmt.Println("RSA-PKCS8私钥生成成功")

// 获取公钥
publicKey := &privateKey.PublicKey

// 将公钥序列化为PKIX格式DER编码
derPublic, err := x509.MarshalPKIXPublicKey(publicKey)
if err != nil {
log.Fatal(err)
}

// 初始化一个PEM编码的结构
pubBlock := &pem.Block{
Type:  "PUBLIC KEY",
Bytes: derPublic,
}



// 创建文件，如果文件存在内容重置为空
file3, err := os.Create(PublicPemFile)
defer file3.Close()
if err != nil {
log.Fatal(err)
}

// 将Block的pem编码写入文件
err = pem.Encode(file3, pubBlock)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA-PKIX公钥生成成功")

derPublic1 := x509.MarshalPKCS1PublicKey(publicKey)

// 初始化一个PEM编码的结构
pubBlock1 := &pem.Block{
Type:  "PUBLIC KEY",
Bytes: derPublic1,
}

// 创建文件，如果文件存在内容重置为空
file4, err := os.Create(PublicPKCS1PemFile)
defer file4.Close()
if err != nil {
log.Fatal(err)
}

// 将Block的pem编码写入文件
err = pem.Encode(file4, pubBlock1)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA-PKCS1公钥生成成功")
}

func getRSAKey() (privateKey []byte, publicKey []byte, err error) {

// 读取publicKey内容
publicKey, err = ioutil.ReadFile(PublicPemFile)
if err != nil {
return
}

// 读取privateKey内容
privateKey, err = ioutil.ReadFile(PrivatePemFile)
return
}

func rsaPKCS1v15Demo() {
// 获取公钥私钥
privateKey, publicKey, err := getRSAKey()
if err != nil {
log.Fatal(err)
}

// 声明内容
var origin = []byte("Hello World!")

// rsa公钥加密
cipherText, err := extra.Encrypt(publicKey, origin)
if err != nil {
log.Fatal(err)
}

// 转base64字符串
cipherTextStr := base64.StdEncoding.EncodeToString(cipherText)
fmt.Println("RSA-PKCS1v15加密内容: ", cipherTextStr)

// rsa私钥解密
originText, err := extra.Decrypt(privateKey, cipherText)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA-PKCS1v15解密内容: ", string(originText))
}

func rsaOAEPDemo() {
// 获取公钥私钥
privateKey, publicKey, err := getRSAKey()
if err != nil {
log.Fatal(err)
}

// 声明内容
var origin = []byte("Hello World!")

// 声明label
var label = []byte("test")

// rsa公钥加密
cipherText, err := extra.EncryptOAEP(publicKey, origin, label)
if err != nil {
log.Fatal(err)
}

// 转base64字符串
cipherTextStr := base64.StdEncoding.EncodeToString(cipherText)
fmt.Println("RSA-OAEP加密内容: ", cipherTextStr)

// rsa私钥解密
originText, err := extra.DecryptOAEP(privateKey, cipherText, label)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA-OAEP解密内容: ", string(originText))
}

func rsaSignatureDemo() {

// 获取公钥私钥
privateKey, publicKey, err := getRSAKey()
if err != nil {
log.Fatal(err)
}

// 声明内容
var origin = []byte("Hello World!")

// rsa私钥签名
signature, err := extra.Sign(privateKey, origin)
if err != nil {
log.Fatal(err)
}

// 转base64字符串
signatureStr := base64.StdEncoding.EncodeToString(signature)
fmt.Println("RSA签名内容: ", signatureStr)

//rsa公钥验签
err = extra.Verify(publicKey, origin, signature)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA签名验证成功")
}

func rsaSignPassDemo() {
// 获取公钥私钥
privateKey, publicKey, err := getRSAKey()
if err != nil {
log.Fatal(err)
}

// 声明内容
var origin = []byte("Hello World!")

// 初始化一个 PSS签名 的参数
var SignOpts = rsa.PSSOptions{SaltLength: 8}

// 初始化一个 PSS认证 的参数
var VerifyOpts = rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto}

// 当PSS签名参数SaltLength 为 rsa.PSSSaltLengthAuto, PSS认证参数SaltLength 必须为 rsa.PSSSaltLengthAuto
// 当PSS签名参数SaltLength 为 rsa.PSSSaltLengthEqualsHash, PSS认证参数SaltLength 为 rsa.PSSSaltLengthAuto或rsa.PSSSaltLengthEqualsHash
// 当PSS签名参数SaltLength 为 指定值时 如8, PSS认证参数SaltLength 为rsa.PSSSaltLengthAuto或8
//

// rsa私钥签名
signature, err := extra.SignPass(privateKey, origin, &SignOpts)
if err != nil {
log.Fatal(err)
}

// 转base64字符串
signatureStr := base64.StdEncoding.EncodeToString(signature)
fmt.Println("RSA-PASS签名内容: ", signatureStr)

//rsa公钥验签
err = extra.VerifyPass(publicKey, origin, signature, &VerifyOpts)
if err != nil {
log.Fatal(err)
}
fmt.Println("RSA-PASS签名验证成功")
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-sha1.go

package main
import (
"crypto"
"crypto/sha1"
"encoding/base64"
"fmt"
)

// 实现了SHA1哈希算法
func main() {
// 返回一个新的使用SHA1校验的hash.Hash
h := sha1.New()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA1
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha1.Sum
m3 := sha1.Sum([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-sha256.go

package main
import (
"crypto"
"crypto/sha256"
"encoding/base64"
"fmt"
)

// 实现了SHA224和SHA256哈希算法
func main() {
sha224Demo()
sha256Demo()
}

func sha224Demo() {
// 返回一个新的使用SHA224校验的hash.Hash
h := sha256.New224()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA224
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha256.Sum224
m3 := sha256.Sum224([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}

func sha256Demo() {
// 返回一个新的使用SHA256校验的hash.Hash
h := sha256.New()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA256
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha256.Sum256
m3 := sha256.Sum256([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-sha512.go

package main
import (
"crypto"
"crypto/sha512"
"encoding/base64"
"fmt"
)

// 实现了SHA384和SHA512哈希算法
func main() {
sha384Demo()
sha512Demo()
sha512_224Demo()
sha512_256Demo()
}

func sha384Demo() {
// 返回一个新的使用SHA384校验的hash.Hash
h := sha512.New384()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA384
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha512.Sum384
m3 := sha512.Sum384([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}

func sha512Demo() {
// 返回一个新的使用SHA512校验的hash.Hash
h := sha512.New()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA512
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha512.Sum512
m3 := sha512.Sum512([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}

func sha512_224Demo() {
// 返回一个新的使用SHA512/224校验的hash.Hash
h := sha512.New512_224()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA512_224
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha512.Sum512_224
m3 := sha512.Sum512_224([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}

func sha512_256Demo() {
// 返回一个新的使用SHA512/256校验的hash.Hash
h := sha512.New512_256()

// 写入
h.Write([]byte("Hello World"))

// 返回添加b到当前的hash值后的新切片，不会改变底层的hash状态
m := h.Sum(nil)

// 转base64字符串打印
fmt.Println(base64.StdEncoding.EncodeToString(m))

// 使用crypto导入
hash := crypto.SHA512_256
h2 := hash.New()
h2.Write([]byte("Hello World"))
m2 := h2.Sum(nil)
fmt.Println(base64.StdEncoding.EncodeToString(m2))

// 直接使用sha512.Sum512_256
m3 := sha512.Sum512_256([]byte("Hello World"))
fmt.Println(base64.StdEncoding.EncodeToString(m3[:]))
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-subtle.go

package main
import "crypto/subtle"

// 实现了在加密代码中常用的功能，但需要仔细考虑才能正确使用
// 比如[]byte中含有验证用户身份的数据（密文哈希、token等）的时候使用
func main() {
var x, y int32 = 6, 8
var a, b byte = 1, 2
var c, d = 1, 2
var e, f = []byte("22"), []byte("33")

// 如果x == y返回1，否则返回0
subtle.ConstantTimeByteEq(a, b)

// 如果x == y返回1，否则返回0
subtle.ConstantTimeEq(x, y)

// 如果x <= y返回1，否则返回0；如果x或y为负数，或者大于2**31-1，函数行为是未定义的
subtle.ConstantTimeLessOrEq(c, d)

// 如果x、y的长度和内容都相同返回1；否则返回0。消耗的时间正比于切片长度而与内容无关
subtle.ConstantTimeCompare(e, f)

// 如果v == 1,则将y的内容拷贝到x；如果v == 0，x不作修改；其他情况的行为是未定义并应避免的
subtle.ConstantTimeCopy(1, e, f)

// 如果v == 1，返回x；如果v == 0，返回y；其他情况的行为是未定义并应避免的
subtle.ConstantTimeSelect(0, c, d)
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-tls.go

package main
import (
"crypto/tls"
"crypto/x509"
"fmt"
"log"
"net"
"time"
)

// 实现了TLS 1.2安全协议
func main() {
var conn net.Conn
// 创建一个新的 证书集合/证书池
roots := x509.NewCertPool()

// 试图解析一系列PEM编码的证书。它将找到的任何证书都添加到证书池中，如果所有证书都成功被解析，会返回true
ok := roots.AppendCertsFromPEM([]byte(RootPEM))
if !ok {

panic("failed to parse root certificate")

}

// 读取并解析一对文件获取公钥和私钥，返回证书链。这些文件必须是PEM编码
cert, err := tls.LoadX509KeyPair("testdata/tls-example-cert.pem", "testdata/tls-example-key.pem")
if err != nil {
log.Fatal(err)
}

// 解析一对PEM编码的数据获取公钥和私钥
cert2, err := tls.X509KeyPair([]byte(CertPem), []byte(KeyPem))
if err != nil {
log.Fatal(err)
}
fmt.Println(cert2)

// TLS客户端或服务端配置
// 在本类型的值提供给TLS函数后，就不应再修改该值。Config类型值可能被重用；tls包也不会修改它
var cfg = &tls.Config{
Certificates:             []tls.Certificate{cert}, // 不少于一个证书的链，用于提供给连接的另一端，服务端必须保证至少有一个证书
Rand:                     nil,                     // Rand提供用于生成随机数和RSA盲签名的熵源，该接口必须能安全的用于并发。如果Rand是nil，会使用crypto/rand包的密码用随机数读取器。
Time:                     nil,                     // Time返回当前时间，如果是nil会使用time.Now
NameToCertificate:        nil,                     // // 映射证书名到证书。注意证书名可以是"*.example.com "的格式，因此证书名不是必须为域名。如果本字段为nil，Certificates字段的第一个成员会被用于所有连接
RootCAs:                  roots,                   // 定义权威根证书，客户端会在验证服务端证书时用到本字段。如果RootCAs是nil，TLS会使用主机的根CA池
NextProtos:               nil,                     // 可以支持的应用层协议的列表
ServerName:               "",                     // 用于认证返回证书的主机名（除非设置了InsecureSkipVerify）。也被用在客户端的握手里，以支持虚拟主机。
ClientAuth:               tls.NoClientCert,        // 决定服务端的认证策略，默认是NoClientCert
ClientCAs:                nil,                     // 定义权威根证书，服务端会在采用ClientAuth策略时使用它来认证客户端证书
InsecureSkipVerify:       true,                    // 控制客户端是否跳过认证服务端的证书链和主机名。如果InsecureSkipVerify为true，TLS连接会接受服务端提供的任何证书和该证书中的任何主机名。此时，TLS连接容易遭受中间人攻击，这种设置只应用于测试
CipherSuites:             nil,                     // 支持的加密组合列表。如果CipherSuites为nil，TLS连接会使用本包的实现支持的密码组合列表
PreferServerCipherSuites: false,                   // 本字段控制服务端是选择客户端最期望的密码组合还是服务端最期望的密码组合。如果本字段为true，服务端会优先选择CipherSuites字段中靠前的密码组合使用
SessionTicketsDisabled:   false,                   // 可以设为false以关闭会话恢复支持
SessionTicketKey:         [32]byte{},                     // 被TLS服务端用于提供会话恢复服务。如果本字段为零值，它会在第一次服务端握手之前填写上随机数据。如果多个服务端都在终止和同一主机的连接，它们应拥有相同的SessionTicketKey。如果SessionTicketKey泄露了，使用该键的之前的记录和未来的TLS连接可能会被盗用
ClientSessionCache:       nil,                     // 是ClientSessionState的缓存，用于恢复TLS会话
MinVersion:               0,                       // 可接受的最低SSL/TLS版本。如果为0，会将SSLv3作为最低版本
MaxVersion:               0,                       // 可接受的最高SSL/TLS版本。如果为0，会将本包使用的版本作为最高版本，目前是TLS 1.2
CurvePreferences:         nil,                     // 用于ECDHE握手的椭圆曲线的ID，按优先度排序。如为空，会使用默认值
}

// 客户端。使用证书访问tls网络
client(roots)
clientWithDialer(roots)

// 服务端。创建一个认证证书的监听
server(cert)

// 使用conn作为下层传输接口返回一个客户端TLS连接。配置参数config必须是非nil的且必须设置了ServerName或者InsecureSkipVerify字段
tls.Client(conn, cfg)

// 使用conn作为下层传输接口返回一个服务端TLS连接。配置参数config必须是非nil的且必须含有至少一个证书
tls.Server(conn, cfg)
}

// 声明根权威证书内容
const RootPEM = `
-----BEGIN CERTIFICATE-----
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
-----END CERTIFICATE-----`

const CertPem = `
-----BEGIN CERTIFICATE-----
MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
6MF9+Yw1Yy0t
-----END CERTIFICATE-----
`

const KeyPem = `
-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
-----END EC PRIVATE KEY-----
`

func client(roots *x509.CertPool) {
// 使用net.Dial连接指定的网络和地址，然后发起TLS握手，返回生成的TLS连接。Dial会将nil的配置视为零值的配置
conn, err := tls.Dial("tcp", "www.baidu.com:443", &tls.Config{RootCAs: roots})
if err != nil {

panic("failed to connect: " + err.Error())

}

// 关闭连接
if err := conn.Close(); err != nil {

panic(err)

}
}

func clientWithDialer(roots *x509.CertPool) {
// 初始化一个net.Dialer,地址建立连接时的参数
dialer := new(net.Dialer)
dialer.Timeout = time.Minute * 2 // dial操作等待连接建立的最大时长，默认值代表没有超时
dialer.Deadline = time.Now().Add(time.Minute * 2) // 一个具体的时间点期限，超过该期限后，dial操作就会失败

// 使用dialer.Dial连接指定的网络和地址，然后发起TLS握手，返回生成的TLS连接。dialer中的超时和期限设置会将连接和TLS握手作为一个整体来应用
conns, err := tls.DialWithDialer(dialer, "tcp", "www.baidu.com:443", &tls.Config{RootCAs: roots})
if err != nil {
log.Fatal(err)
}
if err := conns.Close(); err != nil {
log.Fatal(err)
}
}

func server(cert tls.Certificate) {
// TLS客户端或服务端配置
// 在本类型的值提供给TLS函数后，就不应再修改该值。Config类型值可能被重用；tls包也不会修改它
cfg := &tls.Config{Certificates: []tls.Certificate{cert}}

// 创建一个TLS监听器，使用net.Listen函数接收给定地址上的连接。配置参数config必须是非nil的且必须含有至少一个证书
listener, err := tls.Listen("tcp", ":2000", cfg)
if err != nil {
log.Fatal(err)
}

// 关闭监听，并使任何阻塞的Accept操作都会不再阻塞并返回错误
defer listener.Close()

// 返回该接口的网络地址
listener.Addr()

// 创建一个TLS监听器，该监听器接受inner接收到的每一个连接，并调用Server函数包装这些连接。配置参数config必须是非nil的且必须含有至少一个证书
netListener := tls.NewListener(listener, cfg)
if err := netListener.Close(); err != nil {
log.Fatal(err)
}

for {
// 等待并返回下一个连接到该接口的连接
conn, err := listener.Accept()
if err != nil {
fmt.Println(err)
continue
}
go func(c net.Conn) {
// 在这些完成需要做的事
// 关闭连接
c.Close()
}(conn)
}
}
######################################################################################
D:\go\go\go标准库示例\crypto\crypto-x509.go

package main
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"log"
"math/big"
"net"
"os"
"time"
)

const (
CertFile = "testdata/x509_cert.pem"
KeyFile  = "testdata/x509_key.pem"
)

// 解析X.509编码的证书和密钥
func main() {
// x509.MarshalPKCS1PrivateKey 参考rsa示例中generateRSAKey方法
// x509.MarshalPKCS8PrivateKey 参考rsa示例中generateRSAKey方法
// x509.MarshalPKIXPublicKey   参考rsa示例中generateRSAKey方法
// x509.MarshalPKCS1PublicKey  参考rsa示例中generateRSAKey方法
// x509.ParsePKCS1PrivateKey   参考rsa示例中BuildRSAPKCS1PrivateKey方法
// x509.ParsePKCS8PrivateKey   参考rsa示例中BuildRSAPrivateKey方法
// x509.ParsePKCS1PublicKey    参考rsa示例中BuildRSAPKCS1PublicKey方法
// x509.ParsePKIXPublicKey     参考rsa示例中BuildRSAPublicKey方法
const RootPem = ``

// 创建一个新的 证书集合/证书池
roots := x509.NewCertPool()

// 试图解析一系列PEM编码的证书。它将找到的任何证书都添加到证书池中，如果所有证书都成功被解析，会返回true
roots.AppendCertsFromPEM([]byte(RootPem))

// 添加一个证书
roots.AddCert(new(x509.Certificate))

// 返回池中所有证书的DER编码的持有者的列表
roots.Subjects()

// 生成证书及密钥
createCertificate()

// 通过root证书认证客户端证书
Verify()
}

func createCertificate() {
//把 1 左移 128 位，返回给 big.Int
max := new(big.Int).Lsh(big.NewInt(1), 128)

//返回在 [0, max) 区间均匀随机分布的一个随机值
serialNumber, _ := rand.Int(rand.Reader, max)

// pkix.Name代表一个X.509识别名。只包含识别名的公共属性，额外的属性被忽略
subject := pkix.Name{
Organization:       []string{"Manning Publications Co."},
OrganizationalUnit: []string{"Books"},
CommonName:         "Go Web Programming",
}

// 初始化一个X.509证书
template := x509.Certificate{
SerialNumber: serialNumber, // SerialNumber 是 CA 颁布的唯一序列号，在此使用一个大随机数来代表它
Subject:      subject,
NotBefore:    time.Now(),                                                   // 有效期起始时间
NotAfter:     time.Now().Add(365 * 24 * time.Hour),                         // 有效期截止时间
KeyUsage:     x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, // KeyUsage 与 ExtKeyUsage 用来表明该证书是用来做服务器认证的。代表给定密钥的合法操作集
ExtKeyUsage:  []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},               // 密钥扩展用途的序列
IPAddresses:  []net.IP{net.ParseIP("127.0.0.1")},
}

//生成一对具有指定字位数的RSA密钥
pk, _ := rsa.GenerateKey(rand.Reader, 2048)

// 基于模板创建一个新的证书。会用到模板的如下字段：SerialNumber、Subject、NotBefore、NotAfter、KeyUsage、ExtKeyUsage、UnknownExtKeyUsage、BasicConstraintsValid、IsCA、MaxPathLen、SubjectKeyId、DNSNames、PermittedDNSDomainsCritical、PermittedDNSDomains、SignatureAlgorithm。
//该证书会使用parent签名。如果parent和template相同，则证书是自签名的。Pub参数是被签名者的公钥，而priv是签名者的私钥。
//只支持RSA和ECDSA类型的密钥
//返回的切片是DER编码的证书。
derBytes, _ := x509.CreateCertificate(rand.Reader, &template, &template, &pk.PublicKey, pk)

// 创建cert.pem文件，如果文件存在内容重置为空
certOut, err := os.Create(CertFile)
defer certOut.Close()
if err != nil {
log.Fatal(err)
}

// 初始化一个PEM编码的结构
certBlock := &pem.Block{
Type:  "CERTIFICATE",
Bytes: derBytes,
}

// 将Block的pem编码写入文件
if err := pem.Encode(certOut, certBlock); err != nil {
log.Fatal(err)
}
fmt.Println("Certificate生成成功")

// 创建key.pem文件，如果文件存在内容重置为空
keyOut, _ := os.Create(KeyFile)
defer keyOut.Close()

// 初始化一个PEM编码的结构
keyBlock := &pem.Block{
Type:  "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(pk),
}

// 将Block的pem编码写入文件
if err := pem.Encode(keyOut, keyBlock); err != nil {
log.Fatal()
}
fmt.Println("Key生成成功")
}

func Verify() {
const rootPEM = `
-----BEGIN CERTIFICATE-----
MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
-----END CERTIFICATE-----`

const certPEM = `
-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw
WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp
bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q
5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC
7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa
BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF
BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy
LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz
cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf
BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG
AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t
L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+
gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283
TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq
0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW
RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh
yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
-----END CERTIFICATE-----`

roots := x509.NewCertPool()
ok := roots.AppendCertsFromPEM([]byte(rootPEM))
if !ok {

panic("failed to parse root certificate")

}
block, _ := pem.Decode([]byte(certPEM))
if block == nil {

panic("failed to parse certificate PEM")

}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {

panic("failed to parse certificate: " + err.Error())

}
opts := x509.VerifyOptions{
DNSName: "mail.google.com",
Roots:   roots,
}

if _, err := cert.Verify(opts); err != nil {

panic("failed to verify certificate: " + err.Error())

}
}
######################################################################################
D:\go\go\go标准库示例\databasesql\database-sql.go

package main
import (
"database/sql"
"fmt"
"github.com/go-sql-driver/mysql"
"log"
)

// 提供了保证SQL或类SQL数据库的泛用接口。使用sql包时必须注入（至少）一个数据库驱动
func main() {
// 注册并命名一个数据库，可以在Open函数中使用该命名启用该驱动
// 如果注册同一名称两次，或者driver参数为nil，会导致panic
// 注册mysql驱动，可以直接import引入使用，mysql包的init方法已经做了Register
sql.Register("myMysql", &mysql.MySQLDriver{})

// 查看所有已经注册的驱动
// 返回所有驱动注册名称
fmt.Println(sql.Drivers())

// 提供了一种更简洁的方式来创建 sql.NamedArg
// 可以直接使用sql.NamedArg{}
// NamedArg是一个命名参数。NamedArg值可以用作Query或Exec的参数，并绑定到SQL语句中的相应命名参数
sql.Named("nickname", "")

// 连接数据库, driverName数据库驱动名称，dataSourceName数据库连接信息
db, err := sql.Open("mysql", "root:@tcp(localhost:3306)/test?charset=utf8")
if err != nil {
log.Fatal(err)
}

// 关闭数据库
defer db.Close()

// 返回数据库下层驱动
fmt.Println(db.Driver())

// 检查与数据库的连接是否仍有效，如果需要会创建连接
fmt.Println(db.Ping())

// 设置与数据库建立连接的最大数目
// 如果n大于0且小于最大闲置连接数，会将最大闲置连接数减小到匹配最大开启连接数的限制
// 如果n <= 0，不会限制最大开启连接数，默认为0（无限制）
db.SetMaxOpenConns(0)

// 设置连接池中的最大闲置连接数
// 如果n大于最大开启连接数，则新的最大闲置连接数会减小到匹配最大开启连接数的限制
// 如果n <= 0，不会保留闲置连接
db.SetMaxIdleConns(0)

// 设置连接最大生存时间
// 过期的连接可能会在重用之前被缓慢地关闭
// 如果d <= 0，连接将永久重用
db.SetConnMaxLifetime(0)

// 返回数据库统计信息
stats(db)

// 查询
query(db)

// 查询一行
queryRows(db)

// 执行一次命令，不返回任何结果
exec(db)

// 提前准备一条语句，可用于多次执行数据库操作
prepare(db)

// 事务
transaction(db)
}

func stats(db *sql.DB) {
// 返回数据库统计信息
s := db.Stats()

// 空闲连接数
fmt.Println(s.Idle)

// 当前使用的连接数
fmt.Println(s.InUse)

// 由于setMaxIdleConns而关闭的连接总数
fmt.Println(s.MaxIdleClosed)

// 由于setConnmaxLifetime而关闭的连接总数
fmt.Println(s.MaxLifetimeClosed)

// 与数据库的最大打开连接数
fmt.Println(s.MaxOpenConnections)

// 已建立的在用和空闲的连接数
fmt.Println(s.OpenConnections)

// 等待的总连接数
fmt.Println(s.WaitCount)

// 等待新连接所阻塞的总时间
fmt.Println(s.WaitDuration)
}

func query(db *sql.DB) {
// 查询
// 等同于 db.QueryContext(context.Background(), "select nickname from users where id=?", 1)
rows, err := db.Query("SELECT nickname FROM users WHERE id=?", 1)
if err != nil {
log.Fatal(err)
}

res := make([]string, 0)
// 循环取值
for rows.Next() {
var nickname string

// 赋值，rows中的列的数量必须与值的数量相同
if err := rows.Scan(&nickname); err != nil {
log.Fatal(err)
}
res = append(res, nickname)
}

// 关闭查询
if err := rows.Close(); err != nil {
log.Fatal(err)
}

// 返回扫描赋值时的最后个错误
if err := rows.Err(); err != nil {
log.Fatal(err)
}
fmt.Println(res)
}

func queryRows(db *sql.DB) {
// 查询最多一行信息
// 等同于 db.QueryRowContext(context.Background(), "select nickname from users where id=?", 1)
row := db.QueryRow("SELECT nickname FROM users WHERE id=?", 1)
var name string
if err := row.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Println(name)
}

func exec(db *sql.DB) {
// 执行一次命令（包括查询、删除、更新、插入等），不返回任何执行结果。参数args表示query中的占位参数
// 等同于 db.ExecContext(context.Background(), `select nickname from users where id = 1`)
res, err := db.Exec(`SELECT nickname FROM users WHERE id = 1`)
if err != nil {
log.Fatal(err)
}

// 返回一个数据库生成的回应命令的整数
// 当插入新行时，一般来自一个"自增ID"
// 不是所有的数据库都支持该功能，该状态的语法也各有不同
fmt.Println(res.LastInsertId())

// 返回被update、insert或delete命令影响的行数
// 不是所有的数据库都支持该功能
fmt.Println(res.RowsAffected())
}

func prepare(db *sql.DB) {
// 创建一个准备好的状态用于之后的查询和命令
// 返回值可以同时执行多个查询和命令
stmt, err := db.Prepare("SELECT nickname FROM users WHERE id = ?")
if err != nil {
log.Fatal(err)
}

// 使用提供的参数执行准备好的查询状态，返回Rows类型查询结果
// 其它Query, Exec用法参见db相关方法
row := stmt.QueryRow(1)
var name string
if err := row.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Println(name)
}

func transaction(db *sql.DB) {
// 开启事务
// 等同于 db.BeginTx(context.Background(), nil)
tx, err := db.Begin()
if err != nil {
log.Fatal(err)
}

// 使用提供的参数执行准备好的查询状态，返回Rows类型查询结果
// 其它Query, Exec等用法参见db相关方法
row := tx.QueryRow("SELECT nickname FROM users WHERE id = ?", 1)
var name string
if err := row.Scan(&name); err != nil {
log.Fatal(err)
}
fmt.Println(name)

// 提交事务并关闭
if err := tx.Commit(); err != nil {
log.Fatal(err)
}
// 回滚事务并关闭
//tx.Rollback()
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-ascii85.go

package main
import (
"bytes"
"encoding/ascii85"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
)
// ascii85包实现了ascii85数据编码（5个ascii字符表示4个字节），该编码用于btoa工具和Adobe的PostScript语言和PDF文档格式
func main() {
// 声明内容
var src = []byte("Hello World!")

// 返回字节源数据编码后的最大字节数
num := ascii85.MaxEncodedLen(len(src))

// 初始化一个长度为num的[]byte
var dst = make([]byte, num)

// 将src编码成最多MaxEncodedLen(len(src))数据写入dst，返回实际写入的ascii字节数
// 编码每4字节(5个ascii字符)一段进行一次，最后一个片段采用特殊的处理方式，因此不应将本函数用于处理大数据流的某一独立数据块
ascii85.Encode(dst, src)

// 转base64字符串输出
fmt.Println("Ascii85编码内容: ", base64.StdEncoding.EncodeToString(dst))

// 初始化一个用于接收原始数据的长度为num的[]byte
var origin = make([]byte, num)

// 将src解码后写入dst，返回写入dst的ascii字节数、从src解码的ascii字节数。
// 如果src含有非法数据，函数将返回成功执行的数据（两个数字）和CorruptInputError。
// 如果flush为true，则函数会认为src代表输入流的结尾，完全处理src，而不会等待另一个32字节的数据块
_, _, err := ascii85.Decode(origin, dst, false)
if err != nil {
log.Fatal(err)
}
fmt.Println("Ascii85解码内容: ", string(origin))

// 声明一个buffer
var buf bytes.Buffer

// 创建一个将数据编码为ascii85流写入w的编码器。Ascii85编码算法操作32位块，写入结束后，必须调用Close方法将缓存中保留的不完整块刷新到w里
w := ascii85.NewEncoder(&buf)

// 写入
if _, err := w.Write([]byte("Hello World!")); err != nil {
log.Fatal(err)
}

// 关闭
if err := w.Close(); err != nil {
log.Fatal(err)
}

// 转base64字符串输出
fmt.Println("Ascii85编码内容: ", base64.StdEncoding.EncodeToString(buf.Bytes()))

// 创建一个从r解码ascii85流的解码器
r := ascii85.NewDecoder(&buf)
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println("Ascii85解码内容: ", string(b))
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-asn1.go

package main

import (
"encoding/asn1"
"fmt"
"log"
)

// asn1包实现了DER编码的ASN.1数据结构的解析
func main() {
hello := Hello{
Num: 12,
Str: "Go",
}
// ASN1序列化
/*
	结构体序列化标签可选
	ia5:           使字符串序列化为ASN.1 IA5String类型
	omitempty:     使空切片被跳过
	printable:     使字符串序列化为ASN.1 PrintableString类型
	utf8:          使字符串序列化为ASN.1 UTF8字符串
*/
b, err := asn1.Marshal(hello)
if err != nil {
log.Fatal(err)
}
fmt.Println(b)
var h Hello

// ASN1反序列化，返回未操作的字节切片和一个error
/*
	结构体反序列化标签可选
	application    指明使用了APPLICATION标签
	default:x      设置一个可选整数字段的默认值
	explicit       给一个隐式的标签设置一个额外的显式标签
	optional       标记字段为ASN.1 OPTIONAL的
	set            表示期望一个SET而不是SEQUENCE类型
	tag:x          指定ASN.1标签码，隐含ASN.1 CONTEXT SPECIFIC
*/
if _, err := asn1.Unmarshal(b, &h); err != nil {
log.Fatal(err)
}
fmt.Println(h)
}

type Hello struct {
Num int
Str string
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-base32.go

package main
import (
"bytes"
"encoding/base32"
"fmt"
"io/ioutil"
"log"
)

// 实现了base32编码
func main() {
// 声明内容
var origin = []byte("Hello World!")

// 声明buffer
var buf bytes.Buffer

// 自定一个32字节的字符串
var customEncode = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"

// 使用给出的字符集生成一个*base32.Encoding，字符集必须是32字节的字符串
e := base32.NewEncoding(customEncode)

// 创建一个新的base32流编码器
w := base32.NewEncoder(e, &buf)

// 写入
if _, err := w.Write(origin); err != nil {
log.Fatal(err)
}

// 关闭
if err := w.Close(); err != nil {
log.Fatal(err)
}
fmt.Println("base32编码内容: ", string(buf.Bytes()))

// 创建一个新的base32流解码器
r := base32.NewDecoder(base32.StdEncoding, &buf)

// 读取内容
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println("base32解码内容: ", string(b))

// 使用标准的base32编码字符集编码
originEncode := base32.StdEncoding.EncodeToString(origin)
fmt.Println("base32编码内容: ", originEncode)

// 使用标准的base32编码字符集解码
originBytes, err := base32.StdEncoding.DecodeString(originEncode)
if err != nil {
log.Fatal(err)
}
fmt.Println("base32解码内容: ", string(originBytes))

// 获取数据进行base32编码后的最大长度
var ne = base32.StdEncoding.EncodedLen(len(origin))

// 声明[]byte
var dst = make([]byte, ne)

// 将src的数据编码后存入dst，最多写EncodedLen(len(src))字节数据到dst，并返回写入的字节数
base32.StdEncoding.Encode(dst, origin)
fmt.Println("base32编码内容: ", string(dst))

// 获取base32编码的数据解码后的最大长度
var nd = base32.StdEncoding.DecodedLen(len(dst))

// 声明[]byte
var originText = make([]byte, nd)
if _, err := base32.StdEncoding.Decode(originText, dst); err != nil {
log.Fatal(err)
}
fmt.Println("base32解码内容: ", string(originText))

// base32.HexEncoding 定义用于"扩展Hex字符集"，用于DNS
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-base64.go

package main
import (
"bytes"
"encoding/base64"
"fmt"
"io/ioutil"
"log"
)

// 实现了base64编码
func main() {
// 声明内容
var origin = []byte("Hello World!")

// 声明buffer
var buf bytes.Buffer

// 自定一个64字节的字符串
var customEncode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

// 使用给出的字符集生成一个*base64.Encoding，字符集必须是32字节的字符串
e := base64.NewEncoding(customEncode)

// 创建一个新的base64流编码器
w := base64.NewEncoder(e, &buf)

// 写入
if _, err := w.Write(origin); err != nil {
log.Fatal(err)
}

// 关闭
if err := w.Close(); err != nil {
log.Fatal(err)
}
fmt.Println("base64编码内容: ", string(buf.Bytes()))

// 创建一个新的base64流解码器
r := base64.NewDecoder(base64.StdEncoding, &buf)

// 读取内容
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println("base64解码内容: ", string(b))

// 使用标准的base64编码字符集编码
originEncode := base64.StdEncoding.EncodeToString(origin)
fmt.Println("base64编码内容: ", originEncode)

// 使用标准的base64编码字符集解码
originBytes, err := base64.StdEncoding.DecodeString(originEncode)
if err != nil {
log.Fatal(err)
}
fmt.Println("base64解码内容: ", string(originBytes))

// 获取数据进行base64编码后的最大长度
var ne = base64.StdEncoding.EncodedLen(len(origin))

// 声明[]byte
var dst = make([]byte, ne)

// 将src的数据编码后存入dst，最多写EncodedLen(len(src))字节数据到dst，并返回写入的字节数
base64.StdEncoding.Encode(dst, origin)
fmt.Println("base64编码内容: ", string(dst))

// 获取base64编码的数据解码后的最大长度
var nd = base64.StdEncoding.DecodedLen(len(dst))

// 声明[]byte
var originText = make([]byte, nd)
if _, err := base64.StdEncoding.Decode(originText, dst); err != nil {
log.Fatal(err)
}
fmt.Println("base64解码内容: ", string(originText))

// 创建与enc相同的新编码，指定的填充字符除外，或者nopadding禁用填充。填充字符不能是'\r'或'\n'，不能包含在编码的字母表中，并且必须是等于或小于'\xff'的rune
base64.StdEncoding.WithPadding(base64.StdPadding)

// base64.StdEncoding 定义标准base64编码字符集
// base64.URLEncoding 定义用于URL和文件名的，base64编码字符集
// base64.RawStdEncoding 定义标准无填充字符的base64编码字符集
// base64.RawURLEncoding 定义用于URL和文件名的，无填充字符的base64编码字符集
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-binary.go

package main
import (
"bytes"
"encoding/binary"
"fmt"
"log"
"math"
)

// binary包实现了简单的数字与byte的转换以及变长值的编解
// 数字翻译为定长值来读写，一个定长值，要么是固定长度的数字类型（int8, uint8, int16, float32, complex64, ...）或者只包含定长值的结构体或者数组
// 本包相对于效率更注重简单。如果需要高效的序列化，特别是数据结构较复杂的，请参见更高级的解决方法，例如encoding/gob包，或者采用协议缓存
// 简述：可用于 将uint，float，complex等类型与[]byte类型互相转换
func main() {
// 编码/解码
example()

// 多个数字一起编码/解码
multiExample()

ByteOrder()

uvarint()
}

func example() {
// 指定binary写入时的字节序
// binary.BigEndian 大端字节序的实现
// binary.LittleEndian 小端字节序的实现
var order = binary.LittleEndian

// 声明内容
var data = math.Pi

// 初始化一个buffer
buf := new(bytes.Buffer)

// 将data的binary编码格式写入w，data必须是定长值、定长值的切片、定长值的指针
// order指定写入数据的字节序，写入结构体时，名字中有'_'的字段会置为0
if err := binary.Write(buf, order, data); err != nil {
log.Fatal("binary.Write failed:", err)
}
fmt.Printf("%x\n", buf.Bytes())

var origin float64
// 从r中读取binary编码的数据并赋给data，data必须是一个指向定长值的指针或者定长值的切片
// 从r读取的字节使用order指定的字节序解码并写入data的字段里当写入结构体是，名字中有'_'的字段会被跳过，这些字段可用于填充（内存空间）
if err := binary.Read(buf, order, &origin); err != nil {
log.Fatal("binary.Read failed:", err)
}
fmt.Println(origin)
}

func multiExample() {
// 初始化buffer
buf := new(bytes.Buffer)

// 声明interface{}切片
var data = []interface{}{
uint16(61374),
int8(-54),
uint8(254),
}

// 循环切片按顺序编码写入buf
for _, v := range data {
if err := binary.Write(buf, binary.LittleEndian, v); err != nil {
log.Fatal("binary.Write failed:", err)
}
}
fmt.Printf("%x\n", buf.Bytes())

var origin = struct {
A uint16
B int8
C uint8
}{}

// 解码
if err := binary.Read(buf, binary.LittleEndian, &origin); err != nil {
log.Fatal("binary.Read failed:", err)
}
fmt.Println(origin)
}

func ByteOrder() {
// 声明一个长度为4的[]byte
b := make([]byte, 4)

// 将16比特的无符号整数 转为 字节序列
binary.LittleEndian.PutUint16(b[:2], '1')
binary.LittleEndian.PutUint16(b[2:], 0x07d0)
fmt.Printf("% x\n", b)

// 将字节序列 转为 16比特的无符号整数
x1 := binary.LittleEndian.Uint16(b[:2])
x2 := binary.LittleEndian.Uint16(b[2:])
fmt.Printf("%#04x %#04x\n", x1, x2)
}

func uvarint() {
var n uint64 = 256
// 根据 变长编码N位整数的最大字节数 初始化一个[]byte
buf := make([]byte, binary.MaxVarintLen64)

// 将一个uint64数字编码写入buf并返回写入的长度，如果buf太小，则会panic
binary.PutUvarint(buf, n)

// 从reader读取一个编码后的无符号整数，并返回该整数
i , err := binary.ReadUvarint(bytes.NewReader(buf))
if err != nil {
log.Fatal(err)
}
fmt.Println(i)

// binary.PutVarint binary.ReadVarint 同上
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-csv.go

package main
import (
"bytes"
"encoding/csv"
"fmt"
"io"
"log"
)

// csv读写逗号分隔值（csv）的文件
func main() {
var data = []string{"test", "Hello", "Go"}
var buf bytes.Buffer

// 初始化一个writer
w := csv.NewWriter(&buf)

// 写入
if err := w.Write(data); err != nil {
log.Fatal(err)
}

// 将缓存中的数据写入底层的io.Writer。要检查Flush时是否发生错误的话，应调用Error
w.Flush()

// 抓取错误信息
if err := w.Error(); err != nil {
log.Fatal(err)
}
fmt.Println(string(buf.Bytes()))

// 初始化一个reader
r := csv.NewReader(&buf)
for {
// 从r读取一条记录，返回值record是字符串的切片，每个字符串代表一个字段
record, err := r.Read()
if err == io.EOF { // 判断是否结尾
break
}
if err != nil {
log.Fatal(err)
}
fmt.Println(record)
}

// 从r中读取所有剩余的记录，每个记录都是字段的切片
// 成功的调用返回值err为nil而不是EOF,因为ReadAll方法定义为读取直到文件结尾，因此它不会将文件结尾视为应该报告的错误
// *读取过的记录不会再次被读取
records, err := r.ReadAll()
if err != nil {
log.Fatal(err)
}
fmt.Println(records)
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-gob.go

package main
import (
"bytes"
"encoding/gob"
"fmt"
"log"
)

// gob包管理gob流——在编码器（发送器）和解码器（接受器）之间交换的binary值
// 一般用于传递远端程序调用（RPC）的参数和结果，如net/rpc包就有提供
// 本实现给每一个数据类型都编译生成一个编解码程序，当单个编码器用于传递数据流时，会分期偿还编译的消耗，是效率最高的
func main() {
// 数据编码解码
example()

// 对interface编码解码
exampleInterface()
}

func example() {
var data = "Hello World!"
var data2 = []string{"1", "2", "Hello Go!"}

// 初始化buffer
var buf bytes.Buffer

// 返回一个将编码后数据写入w的*gob.Encoder
enc := gob.NewEncoder(&buf)

// 将e内容编码后发送，并且会保证所有的类型信息都先发送
if err := enc.Encode(data); err != nil {
log.Fatal("encode error:", err)
}
if err := enc.Encode(data2); err != nil {
log.Fatal("encode error:", err)
}

var origin string
var origin2 []string

// 返回一个从r读取数据的*gob.Decoder，如果r不满足io.ByteReader接口，则会包装r为bufio.Reader
dec := gob.NewDecoder(&buf)

// 从输入流读取下一个值并将该值存入e。如果e是nil，将丢弃该值；否则e必须是可接收该值的类型的指针
// 如果输入结束，方法会返回io.EOF并且不修改e（指向的值）
if err := dec.Decode(&origin); err != nil {
log.Fatal("decode error 1:", err)
}
if err := dec.Decode(&origin2); err != nil {
log.Fatal("decode error 2:", err)
}
fmt.Println(origin, origin2)
}

func exampleInterface() {
// 声明buffer
var buf bytes.Buffer

// 记录value下层具体值的类型和其名称
// 该名称将用来识别发送或接受接口类型值时下层的具体类型
// 本函数只应在初始化时调用，如果类型和名字的映射不是一一对应的，会panic
gob.Register(Hello{})

// 初始化一个encoder
enc := gob.NewEncoder(&buf)

// 写入编码数据
interfaceEncode(enc, Hello{"World"})

// 初始化一个decoder
dec := gob.NewDecoder(&buf)

// 读取数据并使用interface的方法
interfaceDecode(dec).Say()
}

type Hello struct {
Name string
}

func (h Hello) Say() { fmt.Println("Hello " + h.Name) }
type Pythagoras interface {
Say()
}

func interfaceEncode(enc *gob.Encoder, p Pythagoras) {
err := enc.Encode(&p)
if err != nil {
log.Fatal("encode:", err)
}
}

func interfaceDecode(dec *gob.Decoder) (p Pythagoras) {
err := dec.Decode(&p)
if err != nil {
log.Fatal("decode:", err)
}
return
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-hex.go

package main
import (
"bytes"
"encoding/hex"
"fmt"
"io/ioutil"
"log"
)

// hex包实现了16进制字符表示的编解码
func main() {
// 编码/解码
example()

example2()

// 编码/解码(string)
exampleString()

// hex dump编码
exampleDump()
}
func example() {
// 声明内容
var src = []byte("Hello Gopher!")

// 声明一个 明文数据编码后的编码数据的长度 的[]byte
dst := make([]byte, hex.EncodedLen(len(src)))

// 将src的数据解码为EncodedLen(len(src))字节，返回实际写入dst的字节数
hex.Encode(dst, src)
fmt.Printf("%s\n", dst)

// 声明一个 编码数据解码后的明文数据的长度 的[]byte
origin := make([]byte, hex.DecodedLen(len(dst)))

// 将src解码为DecodedLen(len(src))字节，返回实际写入dst的字节数；如遇到非法字符，返回描述错误的error
_, err := hex.Decode(origin, dst)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", origin)
}

func example2() {
// 声明内容
var src = []byte("Hello Gopher!")

// 声明buffer
var buf bytes.Buffer



// 创建一个用于编码的writer
w := hex.NewEncoder(&buf)
if _, err := w.Write(src); err != nil {
log.Fatal(err)
}
fmt.Println(string(buf.Bytes()))

// 创建一个用于解码的reader
r := hex.NewDecoder(&buf)

// 读取内容
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}

func exampleString() {
// 声明内容
var src = []byte("Hello Gopher!")

// 将数据src编码为字符串
str := hex.EncodeToString(src)
fmt.Println(str)

// 将十六进制字符串解码为原数据
origin, err := hex.DecodeString(str)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(origin))
}

func exampleDump() {
// 声明内容
content := []byte("Go is an open source programming language.")

// 返回回给定数据的hex dump格式的字符串，这个字符串与控制台下`hexdump -C`对该数据的输出是一致的
str := hex.Dump(content)
fmt.Printf("%s\n", str)

// 声明buffer
var buf bytes.Buffer

// 返回一个io.WriteCloser接口，将写入的数据的hex dump格式写入w，具体格式为'hexdump -C'
dumper := hex.Dumper(&buf)

// 关闭
defer dumper.Close()

// 写入
if _, err := dumper.Write(content); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf.Bytes())
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-json.go

package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
)
// json包实现了json对象的编解码
func main() {
// 声明内容
var data = []byte(`{"message": "Hello Gopher!"}`)

// 验证内容是否符合json格式
json.Valid(data)

example()

example2()
}

type Hello struct {
Name string
Sex  int
}

func example() {
// 声明一个结构体
hello := Hello{"Gopher", 1}

// 进行json编码
b, err := json.Marshal(hello)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))

// 声明一个空的结构体
originHello := Hello{}

// 将json内容解码到指定结构中
if err := json.Unmarshal(b, &originHello); err != nil {
log.Fatal(err)
}
fmt.Println(originHello)
}

func example2() {
// 声明buffer
var buf bytes.Buffer

// 声明一个结构体
hello := Hello{"<div>World</div>", 2}

// 创建一个将数据写入w的*Encoder
e := json.NewEncoder(&buf)

// 是否转义html标签, 例如：&, <, > 为\u0026, \u003c, \u003e
e.SetEscapeHTML(false)

// 设置缩进(可以随意设置缩进内容)
e.SetIndent("", "")

// 进行json编码
if err := e.Encode(hello); err != nil {
log.Fatal(err)
}
fmt.Println(string(buf.Bytes()))

// 声明一个空的结构体
originHello := Hello{}

// 创建一个从r读取并解码json对象的*Decoder
d := json.NewDecoder(&buf)

// 返回保存在json.Decoder缓存里数据的读取器，该返回值在下次调用Decode方法之前有效
d.Buffered()

// 设置此项，如果发现不能识别的字符串将导致解码失败
d.DisallowUnknownFields()

// 设置此项，当接收端是interface{}接口时将json数字解码为Number类型而不是float64类型
d.UseNumber()

// 返回是否存在其他元素
d.More()

// 将json内容解码到指定结构中
if err := d.Decode(&originHello); err != nil {
log.Fatal(err)
}
fmt.Println(originHello)
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-pem.go

package main
import (
"bytes"
"encoding/pem"
"fmt"
"log"
)

// pem包实现了PEM数据编码（源自保密增强邮件协议）。目前PEM编码主要用于TLS密钥和证书
func main() {
// 声明buffer
var buf bytes.Buffer

// 初始化一个PEM编码的结构
block := &pem.Block{
Type:    "PUBLIC KEY",   // 类型
Headers: map[string]string{
"author": "zc",
"name": "Gopher",
},            // 可选的头项
Bytes:   []byte("test"), // 内容解码后的数据，一般是DER编码的ASN.1结构
}

// 将Block的pem编码写入writer
if err := pem.Encode(&buf, block); err != nil {
log.Fatal(err)
}
fmt.Println(string(buf.Bytes()))

// pem解码返回一个PEM结构 和 未解码数据
dk, _ := pem.Decode(buf.Bytes())
fmt.Println(dk)
}
######################################################################################
D:\go\go\go标准库示例\encoding\encoding-xml.go

package main
import (
"bytes"
"encoding/xml"
"fmt"
"log"
)

// xml包实现了XML 1.0解析
func main() {
example()

example2()
}

type Hello struct {
XMLName   xml.Name `xml:"xml"`        // 指定xml头标签,不指定默认为结构体名称
Id        int      `xml:"id,attr"`    // 指定xml头标签上的元素
FullName  string   `xml:"fullName"`   // 指定标签名
FirstName string   `xml:"name>first"` // 指定上级标签
LastName  string   `xml:"name>last"`  // 指定上级标签
Sex       int      `xml:"sex"`        // 指定标签名
Comment   string   `xml:",comment"`   // 声明注释
}

func example() {
// 声明结构体
hello := Hello{
Id:        12,
FullName:  "zc",
FirstName: "z",
LastName:  "c",
Sex:       1,
Comment:   "test notes",
}

// xml编码
b, err := xml.Marshal(hello)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))

// 声明一个空的结构体
origin := Hello{}
if err := xml.Unmarshal(b, &origin); err != nil {
log.Fatal(err)
}
fmt.Println(origin)

// 自定义前缀和index编码
bi, err := xml.MarshalIndent(hello, "\r", "  ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(bi))
}

func example2() {
// 声明buffer
var buf bytes.Buffer

// 声明结构体
hello := Hello{
Id:        12,
FullName:  "zc",
FirstName: "z",
LastName:  "c",
Sex:       1,
Comment:   "test notes",
}

// 创建一个写入w的*Encoder
e := xml.NewEncoder(&buf)

// 自定义前缀和index
e.Indent("\r", "  ")

// 自定义xml头编码
err := e.EncodeElement(hello, xml.StartElement{
Name: xml.Name{
Space: "test",   // xmlns
Local: "newXml", // xml头名称
},
Attr: nil, // 设置xml头元素
})
if err != nil {
log.Fatal(err)
}
fmt.Println(string(buf.Bytes()))
}
######################################################################################
D:\go\go\go标准库示例\errors\errors.go

package main
import (
"errors"
"fmt"
)

type CustomError string
func (e CustomError) Error() string { return string(e) }
func (e CustomError) Unwrap() error { return errors.New("unwrap error") }
func (e CustomError) As(err error) bool { return true }

func main() {
// 新建error
err := errors.New("test error")
fmt.Println(err)
ce := CustomError("test error1")
fmt.Println(errors.Is(err, ce))
var e error
fmt.Println(errors.As(ce, &e), e)
fmt.Println(errors.Unwrap(ce))
}
######################################################################################
D:\go\go\go标准库示例\expvar\expvar.go

package main
import (
"expvar"
"fmt"
)

// 公共变量，例如可用做服务的操作计数器
func main() {
// 创建float类型的公共变量
expvar.NewFloat("testFloat")

// 创建string类型的公共变量
expvar.NewString("testStr")

// 创建int类型的公共变量
i := expvar.NewInt("testInt")

// 设置变量值
i.Set(16)

// 原有变量加上一个变量
i.Add(15)

// 返回该变量类型值
i.Value()

// 返回该变量的string类型值
i.String()

// 创建map类型的公共变量
m := expvar.NewMap("testMap")

// 重置为一个初始的空map
m.Init()

// 设置map键值对
m.Set("k1", i)

// 为map指定键的值加上delta值，键值必须为int类型
m.Add("k1", 5)

// 为map指定键的值加上delta值，键值必须为float类型
m.AddFloat("k2", 5.2)

// 返回map字符串
m.String()

// 获取map指定键的expvar.Val值
v := m.Get("k1")
v.String()

// 根据键删除指定键值对
m.Delete("k2")

// 为map下每组键值对调用指定方法
m.Do(func(kv expvar.KeyValue) {
fmt.Println(kv.Key, kv.Value.String())
})

// 获取公共变量Var值
expvar.Get("testInt")

// 为每组公共变量调用指定方法
expvar.Do(func(kv expvar.KeyValue) {
fmt.Println(kv.Key, kv.Value.String())
})

// 返回一个http.Handler
expvar.Handler()
}

func init() {
// 使用expvar.Fun结构返回值
pbInt := func() interface{} {
return 12
}
// 声明一个导出变量，必须在init函数里调用，如果变量名存在则调用log.Panic
expvar.Publish("pbInt", expvar.Func(pbInt))
}
######################################################################################
D:\go\go\go标准库示例\flag\flag.go

package main
import (
"flag"
"fmt"
"log"
"reflect"
"strconv"
"time"
)

// 命令行参数解析
func main() {
// 返返回解析之后剩下的非flag参数(不包括命令名)
flag.Args()

// 返回解析之后剩下的第i个参数，从0开始索引
flag.Arg(2)

// 返回解析flag之后剩余参数的个数
flag.NArg()

// 返回解析时进行了设置的flag的数量
flag.NFlag()

// 从Args中解析注册的flag。必须在所有flag都注册好而未访问其值时执行。未注册却使用flag -help时，会返回ErrHelp。
flag.Parse()

// 返回是否flag.Parse已经被调用过
flag.Parsed()

// 创建一个新的指定名称，指定错误处理策略的FlagSet。
fg := flag.NewFlagSet("test", flag.PanicOnError)

// 解析flag出现错误时会被调用
fg.Usage = func() {
log.Fatal("异常")
}

// fg.Int等同于直接调用flag.Int，其它类型也相同
// 用指定名称、默认值、使用信息，注册一个int类型flag。返回一个保存了该flag的值的指针
flag.Int("i", 2, "int flag")

// 用指定名称、默认值、使用信息，注册一个int类型flag，并将flag的值保存到p指向的变量
var i int
flag.IntVar(&i, "i", 2, "int flag")
var i64 int64
flag.Int64("i64", 64, "int64 flag")
flag.Int64Var(&i64, "i64", 64, "int64 flag")
var f float64
flag.Float64("f", 6.4, "float64 flag")
flag.Float64Var(&f, "f", 6.4, "float64 flag")
var s string
flag.String("s", "str", "string flag")
flag.StringVar(&s, "s", "str", "string flag")
var b bool
flag.Bool("b", true, "bool flag")
flag.BoolVar(&b, "b", true, "bool flag")
var u uint
flag.Uint("u", 5, "uint flag")
flag.UintVar(&u, "u", 5, "uint flag")
var u64 uint64
flag.Uint64("u64", 5, "uint64 flag")
flag.Uint64Var(&u64, "u64", 5, "uint64 flag")
var d time.Duration
flag.Duration("d", time.Second, "duration flag")
flag.DurationVar(&d, "d", time.Second, "duration flag")

// 设置已注册的flag的值
err := flag.Set("s", "test")
if err != nil {
log.Fatal(err)
}

// 返回已经已注册flag的Flag结构体指针；如果flag不存在的话，返回nil
fl := flag.Lookup("s")
fmt.Println(fl.Usage)          // 使用说明
fmt.Println(fl.Value.String()) // 要设置的值
fmt.Println(fl.Name)           // 在命令行中的名称
fmt.Println(fl.DefValue)       // 默认值

// 返回引用名称和用法。根据flag的Flag结构，从用法中提取反向引用的名称，如果没有名称为值可能的类型，如果是布尔值则为空字符串
flag.UnquoteUsage(fl)

// 用指定名称、使用信息，注册一个flag。该flag的类型的值由第一个参数表示，该参数应实现了Value接口。例如，用户可以创建一个flag，可以用Value接口的Set方法将逗号分隔的字符串转化为字符串切片。
var ni newVal = 2
flag.Var(ni, "new", "it is a new flag")

// 按照字典顺序遍历标签，并且对每个标签调用fn。 这个函数只遍历解析时进行了设置的标签
flag.Visit(func(f *flag.Flag) {
fmt.Println(f.Name)
})

// 按照字典顺序遍历标签，并且对每个标签调用fn。 这个函数会遍历所有标签，不管解析时有无进行设置
flag.VisitAll(func(f *flag.Flag) {
fmt.Println(f.Name)
})
}

type newVal int
func (v newVal) String() string {
val := reflect.ValueOf(v)
return strconv.Itoa(int(val.Int()))
}

func (v newVal) Set(s string) error {
i, err := strconv.Atoi(s)
val := reflect.ValueOf(v)
val.SetInt(int64(i))
return err
}
######################################################################################
D:\go\go\go标准库示例\fmt\fmt.go

package main
import (
"bytes"
"fmt"
)

// fmt包实现了类似C语言printf和scanf的格式化I/O。格式化动作（'verb'）源自C语言但更简单
func main() {
var buf bytes.Buffer
var str string

// 采用默认格式将其参数格式化并写入标准输出
// 总是会在相邻参数的输出之间添加空格并在输出结束后添加换行符
// 返回写入的字节数和遇到的任何错误
fmt.Println("打印内容", "Hello World!")

// 采用默认格式将其参数格式化并写入标准输出
// 如果两个相邻的参数都不是字符串，会在它们的输出之间添加空格
// 返回写入的字节数和遇到的任何错误
fmt.Print("打印内容", "Hello World!", "\n")

// 根据format参数生成格式化的字符串并写入标准输出
// 返回写入的字节数和遇到的任何错误
/*
	%b  二进制
	%o  八进制
	%d  十进制
	%x	十六进制
	%f	浮点数 3.141593
	%g  浮点数 3.141592653589793
	%e	浮点数 3.141593e+00
	%t 	布尔值
	%c  字符(rune)
	%s  字符串
	%q  带双引号的字符串"abc"或带单引号的'c'
	%v  变量的自然形式
	%T  变量的类型
	%%  字面上的%号标志
*/

fmt.Printf("打印内容%s", "Hello World!\n")

// 采用默认格式将其参数格式化并写入w
// 总是会在相邻参数的输出之间添加空格并在输出结束后添加换行符
// 返回写入的字节数和遇到的任何错误
fmt.Fprintln(&buf, "Hello", "World!")

// 采用默认格式将其参数格式化并写入w
// 如果两个相邻的参数都不是字符串，会在它们的输出之间添加空格
// 返回写入的字节数和遇到的任何错误
fmt.Fprint(&buf, "Hello", "World!")

// 根据format参数生成格式化的字符串并写入w
// 返回写入的字节数和遇到的任何错误
fmt.Fprintf(&buf, "Hello %s", "World!")

// 采用默认格式将其参数格式化，串联所有输出生成 并 返回一个字符串
// 总是会在相邻参数的输出之间添加空格并在输出结束后添加换行符
fmt.Sprintln("Hello", "World!")

// 采用默认格式将其参数格式化，串联所有输出生成 并 返回一个字符串
// 如果两个相邻的参数都不是字符串，会在它们的输出之间添加空格
fmt.Sprint("Hello", "World!")

// 根据format参数生成格式化的字符串 并 返回该字符串
fmt.Sprintf("Hello %s", "World!")

// 根据format参数生成格式化字符串并返回一个包含该字符串的错误
fmt.Errorf("%s", "Error")

// 从标准输入扫描文本，将成功读取的空白分隔的值保存进成功传递给本函数的参数
// 换行视为空白。返回成功扫描的条目个数和遇到的任何错误
// 如果读取的条目比提供的参数少，会返回一个错误报告原因
fmt.Scan("Hello", "World!")

// 类似Scan，但会在换行时才停止扫描。最后一个条目后必须有换行或者到达结束位置
fmt.Scanln("Hello", "World!")

// 从标准输入扫描文本，根据format 参数指定的格式将成功读取的空白分隔的值保存进成功传递给本函数的参数
// 返回成功扫描的条目个数和遇到的任何错误。
fmt.Scanf("%s", "Hello")

// 从r扫描文本，将成功读取的空白分隔的值保存进成功传递给本函数的参数
// 换行视为空白。返回成功扫描的条目个数和遇到的任何错误
// 如果读取的条目比提供的参数少，会返回一个错误报告原因
fmt.Fscan(&buf, "Hello", "World!")

// 类似Fscan，但会在换行时才停止扫描。最后一个条目后必须有换行或者到达结束位置
fmt.Fscanln(&buf, "Hello", "World!")

// 从r扫描文本，根据format 参数指定的格式将成功读取的空白分隔的值保存进成功传递给本函数的参数
// 返回成功扫描的条目个数和遇到的任何错误
fmt.Fscanf(&buf, "%s", "Hello")

// 从字符串str扫描文本，将成功读取的空白分隔的值保存进成功传递给本函数的参数
// 换行视为空白。返回成功扫描的条目个数和遇到的任何错误
// 如果读取的条目比提供的参数少，会返回一个错误报告原因
fmt.Sscan(str, "Hello", "World!")

// 类似Sscan，但会在换行时才停止扫描。最后一个条目后必须有换行或者到达结束位置
fmt.Sscanln(str, "Hello", "World!")

// 从字符串str扫描文本，根据format 参数指定的格式将成功读取的空白分隔的值保存进成功传递给本函数的参数
// 返回成功扫描的条目个数和遇到的任何错误
fmt.Sscanf(str, "%s", "Hello")
}
######################################################################################
D:\go\go\go标准库示例\hash\hash-adler32.go

package main
import (
"encoding/hex"
"fmt"
"hash/adler32"
"log"
)

// adler32包实现了Adler-32校验和算法
// Adler-32由两个每字节累积的和组成：s1是所有字节的累积，s2是所有s1的累积。两个累积值都取65521的余数。s1初始为1，s2初始为0。Afler-32校验和保存为s2*65536 + s1。（最高有效字节在前/大端在前）
func main() {
// 声明内容
var data = []byte("Hello World!")

// 返回数据data的Adler-32校验和
cipherText := adler32.Checksum(data)
fmt.Println(cipherText)

// 返回一个计算Adler-32校验和的hash.Hash32接口
h := adler32.New()
// 写入
if _, err := h.Write(data); err!= nil {
log.Fatal(err)
}
hb := h.Sum(nil)
fmt.Println(hex.EncodeToString(hb))
}
######################################################################################
D:\go\go\go标准库示例\hash\hash-crc32.go

package main
import (
"fmt"
"hash/crc32"
"log"
)

// crc32包实现了32位循环冗余校验（CRC-32）的校验和算法
func main() {
// 声明内容
var data = []byte("Hello World!")
var p = []byte("test")

// 创建一个使用IEEE多项式计算CRC-32校验和的hash.Hash32接口
h := crc32.NewIEEE()

// 写入
if _, err := h.Write(data); err != nil {
log.Fatal(err)
}

// 返回uint32值
s := h.Sum32()
fmt.Println(s)

// 返回一个代表poly指定的多项式的Table
// crc32.IEEE        最常用的CRC-32多项式；用于以太网、v.42、fddi、gzip、zip、png、mpeg-2……
// crc32.Castagnoli  卡斯塔尼奥利多项式，用在iSCSI；有比IEEE更好的错误探测特性
// crc32.Koopman     库普曼多项式；错误探测特性也比IEEE好
t := crc32.MakeTable(crc32.IEEE)

// 返回数据data使用tab代表的多项式计算出的CRC-32校验和
crc32.Checksum(data, t)

// 返回数据data使用IEEE多项式计算出的CRC-32校验和
crc32.ChecksumIEEE(data)

// 返回将切片p的数据采用tab表示的多项式添加到crc之后计算出的新校验和
crc32.Update(s, t, p)

// 创建一个使用tab代表的多项式计算CRC-32校验和的hash.Hash32接口
crc32.New(t)
}
######################################################################################
D:\go\go\go标准库示例\hash\hash-crc64.go

package main
import "hash/crc64"

// crc64包实现64位循环冗余校验或 CRC-64 校验和
func main() {
// 声明内容
var data = []byte("Hello World!")

var p = []byte("test")

// 返回一个代表poly指定的多项式的*Table
// crc64.ISO  ISO 3309定义的ISO多项式，用于HDLC
// crc64.ECMA ECMA 182定义的ECMA多项式
t := crc64.MakeTable(crc64.ISO)

// 返回数据data使用tab代表的多项式计算出的CRC-64校验和
c := crc64.Checksum(data, t)

// 返回将切片p的数据采用tab表示的多项式添加到crc之后计算出的新校验和
crc64.Update(c, t, p)

// 创建一个使用tab代表的多项式计算CRC-64校验和的hash.Hash64接口
crc64.New(t)
}
######################################################################################
D:\go\go\go标准库示例\hash\hash-fnv.go

package main
import (
"fmt"
"hash/fnv"
"log"
)

// fnv包实现了FNV-1和FNV-1a（非加密hash函数）
func main() {
var data = []byte("Hello World!")

// 返回一个新的32位FNV-1的hash.Hash32接口
h := fnv.New32()

// 写入
if _, err := h.Write(data); err != nil {
log.Fatal(err)
}
fmt.Println(h.Sum32())

// 返回一个新的32位FNV-1a的hash.Hash32接口
fnv.New32a()

// 返回一个新的64位FNV-1的hash.Hash64接口
fnv.New64()

// 返回一个新的64位FNV-1a的hash.Hash64接口
fnv.New64a()

//返回一个新的128位FNV-1的hash.Hash64接口
fnv.New128()

// 返回一个新的128位FNV-1a的hash.Hash64接口
fnv.New128a()
}
######################################################################################
D:\go\go\go标准库示例\html\html-template.go

package main

// template包（html/template）实现了数据驱动的模板，用于生成可对抗代码注入的安全HTML输出
// 本包提供了和text/template包相同的接口，无论何时当输出是HTML的时候都应使用本包
// 此处的文档关注本包的安全特性。至于如何使用模板，请参照text/template包
// 本包是对text/template包的包装，两个包提供的模板API几无差别，可以安全的随意替换两包

func main() {

// 参考text/template
}
######################################################################################
D:\go\go\go标准库示例\html\html.go

package main

import (
"fmt"
"html"
)

// html包提供了用于转义和解转义HTML文本的函数

func main() {
var data = "<div>Hello World!</div>"

// 将特定的一些字符转为逸码后的字符实体，如"<"变成"&lt;"
// 它只会修改五个字符：<、>、&、'、"
// UnescapeString(EscapeString(s)) == s总是成立，但是两个函数顺序反过来则不一定成立
str := html.EscapeString(data)
fmt.Println(str)

// 将逸码的字符实体如"&lt;"修改为原字符"<"
// 它会解码一个很大范围内的字符实体，远比函数EscapeString转码范围大得多。例如"&aacute;"解码为"á"，"&#225;"和"&xE1;"也会解码为该字符
origin := html.UnescapeString(str)
fmt.Println(origin)
}
######################################################################################
D:\go\go\go标准库示例\image\image.go

package main
import (
"fmt"
"image"
"image/color"
"image/jpeg"
"image/png"
"log"
"math"
"os"
)

// image实现了基本的2D图片库
// 基本接口叫作Image。图片的色彩定义在image/color包。
// Image接口可以通过调用如NewRGBA和NewPaletted函数等获得；也可以通过调用Decode函数解码包含GIF、JPEG或PNG格式图像数据的输入流获得
// 解码任何具体图像类型之前都必须注册对应类型的解码函数
// 注册过程一般是作为包初始化的副作用，放在包的init函数里。因此，要解码PNG图像，只需在程序的main包里嵌入  import _ "image/png"
func main() {
// png图片生成
examplePngEncode()

// png图片解析
examplePngDecode()

exampleJpegEncode()
}

const (
PngFilePath = "testdata/rgb.png"
JpegFilePath = "testdata/rgb.jpeg"
GifFilePath = "testdata/rgb.gif"
)

type Circle struct {
X, Y, R float64
}

func (c *Circle) Brightness(x, y float64) uint8 {
var dx, dy = c.X-x, c.Y-y
d := math.Sqrt(dx*dx+dy*dy) / c.R
if d > 1 {

return 0

} else {

return 255

}
}

func createRGBAImage() *image.RGBA {
// 指定长宽
var w, h = 280, 240
var hw, hh = float64(w/2), float64(h/2)
r := 40.0

// 三分之二的圆周率
p := 2 * math.Pi / 3

// 红色圆
cr := &Circle{hw - r*math.Sin(0), hh - r*math.Cos(0), 60}

// 绿色圆
cg := &Circle{hw - r*math.Sin(p), hh - r*math.Cos(p), 60}

// 蓝色圆
cb := &Circle{hw - r*math.Sin(-p), hh - r*math.Cos(-p), 60}

// 指定两个坐标点生成矩形
// Rect是Rectangle {Pt（x0，y0），Pt（x1，y1）}的简写
// 返回的矩形具有必要时交换的最小和最大坐标，以便格式良好
rect := image.Rect(0, 0, w, h)

// 初始化一张NRGBA图片
m := image.NewRGBA(rect)

// 为图片上每个点设置颜色
for x := 0; x < w; x++ {
for y := 0; y < h; y++ {
c := color.RGBA{
R: cr.Brightness(float64(x), float64(y)),
G: cg.Brightness(float64(x), float64(y)),
B: cb.Brightness(float64(x), float64(y)),
A: 255,
}
m.Set(x, y, c)
}
}
return m
}

func examplePngEncode() {
// 生成RGBA图片内容
m := createRGBAImage()

// 创建并打开一个只能写入的png文件
f, err := os.OpenFile(PngFilePath, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()

// 将RGBA内容编码成png写入文件
if err := png.Encode(f, m); err != nil {
log.Fatal(err)
}
}

func examplePngDecode() {
// 打开png文件
f, err := os.Open(PngFilePath)
if err != nil {
log.Fatal(err)
}

// png解码
img, err := png.Decode(f)
if err != nil {
log.Fatal(err)
}

levels := []string{" ", "░", "▒", "▓", "█"}
// Bounds返回图片域，边界不一定包含点（0，0）
for y := img.Bounds().Min.Y; y < img.Bounds().Max.Y; y++ {
for x := img.Bounds().Min.X; x < img.Bounds().Max.X; x++ {

// at返回像素在（x，y）处的颜色
// at（bounds（）.min.x，bounds（）.min.y）返回网格的左上角像素
// at（bounds（）.max.x-1，bounds（）.max.y-1）返回右下角的像素
pointColor := img.At(x, y)

// 使用灰度色覆盖
c := color.GrayModel.Convert(pointColor).(color.Gray)
level := c.Y / 51 // 51 * 5 = 255
if level == 5 {
level--
}
fmt.Print(levels[level])
}
fmt.Print("\n")
}
}

func exampleJpegEncode() {
// 生成RGBA图片内容
m := createRGBAImage()

// 创建并打开一个只能写入的jpeg文件
f, err := os.OpenFile(JpegFilePath, os.O_WRONLY|os.O_CREATE, 0600)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()

// 将RGBA内容编码成jpeg写入文件
// Options图像质量值为100，是最好的图像显示
if err := jpeg.Encode(f, m, &jpeg.Options{100}); err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\index-suffixarray\index-suffixarray.go

package main
import (
"bytes"
"index/suffixarray"
"regexp"
)

// suffixarray包通过使用内存中的后缀树实现了对数级时间消耗的子字符串搜索。
func main() {
// 声明buffer
var buf bytes.Buffer

// 声明内容
var data = []byte("Hello Gopher!")
var src = []byte("Gopher")

// 生成一个*Index，时间复杂度O(N*log(N))。
index := suffixarray.New(data)

// 返回创建x时提供的[]byte数据，注意不能修改返回值
index.Bytes()

// 从reader中读取一个index写入x，x不能为nil
index.Read(&buf)

// 将x中的index写入writer中，x不能为nil
index.Write(&buf)

// 返回一个未排序的列表，内为s在被索引为index的切片数据中出现的位置
// 如果n<0，返回全部匹配；如果n==0或s为空，返回nil；否则n为result的最大长度
// 时间复杂度O(log(N)*len(s) + len(result))，其中N是被索引的数据的大小
index.Lookup(src, -1)

// 返回一个正则表达式r的不重叠的匹配的经过排序的列表，一个匹配表示为一对指定了匹配结果的切片的索引（相对于x.Bytes())
// 如果n<0，返回全部匹配；如果n==0或匹配失败，返回nil；否则n为result的最大长度
index.FindAllIndex(regexp.MustCompile(`\d*`), -1)
}
######################################################################################
D:\go\go\go标准库示例\io\io-ioutil.go

package main
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
)

const Dir = "testdata/testDir"
const File = "testdata/test"
// ioutil包实现了一些 I/O 实用程序功能
func main() {
// 声明内容
var data = []byte("Go is a general-purpose language designed with systems programming in mind.")

// 创建一个reader
var r = bytes.NewReader(data)

// 从r读取数据直到EOF或遇到error，返回读取的数据和遇到的错误
// 成功的调用返回的err为nil而非EOF
// 因为本函数定义为读取r直到EOF，它不会将读取返回的EOF视为应报告的错误
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))

// 向filename指定的文件中写入数据。如果文件不存在将按给出的权限创建文件，否则在写入数据之前清空文件
_ = ioutil.WriteFile(File, data, os.ModePerm)

// 从filename指定的文件中读取数据并返回文件的内容
// 成功的调用返回的err为nil而非EOF
// 因为本函数定义为读取整个文件，它不会将读取返回的EOF视为应报告的错误
bf, err := ioutil.ReadFile(File)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(bf))

// 返回dirname指定的目录的目录信息的有序列表
files, err := ioutil.ReadDir(Dir)
if err != nil {
log.Fatal(err)
}
for _, file := range files {

// 文件名称(不含扩展名)
fmt.Println(file.Name())

// 修改时间
fmt.Println(file.ModTime())

// 文件模式
fmt.Println(file.Mode())

// 判断是否是一个目录，等价于Mode().IsDir()
fmt.Println(file.IsDir())

// 普通文件返回值表示其大小；其他文件的返回值含义各系统不同
fmt.Println(file.Size())

// 基础数据源（可以返回nil）
fmt.Println(file.Sys())
}

// 用一个无操作的Close方法包装r返回一个ReadCloser接口
rc := ioutil.NopCloser(r)
if err := rc.Close(); err != nil {
log.Fatal(err)
}

// 创建temp文件
exampleTempFile()

// 创建temp目录
exampleTempDir()
}

func exampleTempDir() {
content := []byte("temporary file's content")

// 在dir目录里创建一个新的、使用prfix作为前缀的临时文件夹，并返回文件夹的路径
// 如果dir是空字符串，TempDir使用默认用于临时文件的目录（参见os.TempDir函数）
// 不同程序同时调用该函数会创建不同的临时目录，调用本函数的程序有责任在不需要临时文件夹时摧毁它
dir, err := ioutil.TempDir("", "example")
if err != nil {
log.Fatal(err)
}

// 移除文件夹
defer os.RemoveAll(dir)

// 将新的文件夹路径放入一个单一路径里
tmpfn := filepath.Join(dir, "tmpfile")
if err := ioutil.WriteFile(tmpfn, content, 0666); err != nil {
log.Fatal(err)
}
}

func exampleTempFile() {
data := []byte("temporary file's content")

// 在dir目录下创建一个新的、使用prefix为前缀的临时文件，以读写模式打开该文件并返回os.File指针
// 如果dir是空字符串，TempFile使用默认用于临时文件的目录（参见os.TempDir函数）
// 不同程序同时调用该函数会创建不同的临时文件，调用本函数的程序有责任在不需要临时文件时摧毁它
tmpFile, err := ioutil.TempFile("", "example")
if err != nil {
log.Fatal(err)
}

// 移除文件
defer os.Remove(tmpFile.Name())

// 写入
if _, err := tmpFile.Write(data); err != nil {
log.Fatal(err)
}

// 关闭
if err := tmpFile.Close(); err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\io\io.go

package main
import (
"bytes"
"fmt"
"io"
"log"
"os"
"strings"
)

// io包提供了对I/O原语的基本接口
// 本包的基本任务是包装这些原语已有的实现（如os包里的原语），使之成为共享的公共接口，这些公共接口抽象出了泛用的函数并附加了一些相关的原语的操作
// 因为这些接口和原语是对底层实现完全不同的低水平操作的包装，除非得到其它方面的通知，客户端不应假设它们是并发执行安全的
func main() {
// 读取reader内容向指定大小buffer填充
exampleReadFull()

// 向writer中写入字符串
exampleWriteString()

// writer拷贝reader内容
exampleCopy()

// writer拷贝reader指定字节数的内容
exampleCopayN()

// writer拷贝reader内容，提供指定大小的缓冲区
exampleCopyBuffer()

// 从reader读取至少n字节的内容填充指定大小的buffer
exampleReadAtLeast()

// 从reader中读取n个字节并返回一个新的reader
exampleLimitReader()

// 将几个reader内容串联起来并返回一个新的reader
exampleMultiReader()

// 返回一个将其从r读取的数据写入w的Reader接口。所有通过该接口对r的读取都会执行对应的对w的写入
exampleTeeReader()

// 返回一个从reader第off个字节开始往后n个的内容的新reader
exampleSectionReader()

// 创建一个可以同时写入多个writer的writer接口
exampleMultiWriter()

// 管道实例
examplePipe()
}

func exampleReadFull() {
// 根据字符串创建一个reader
r := strings.NewReader("some io.Reader stream to be read\n")

// 声明4个字节的buffer
buf := make([]byte, 4)

// 从reader精确地读取len(buf)字节数据填充进buffer
// 函数返回写入的字节数和错误（如果没有读取足够的字节）
// 只有没有读取到字节时才可能返回EOF；如果读取了有但不够的字节时遇到了EOF，函数会返回ErrUnexpectedEOF
// 只有返回值err为nil时，返回值n才会等于len(buf)
if _, err := io.ReadFull(r, buf); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
}

func exampleWriteString() {
var buf bytes.Buffer

// 将字符串s的内容写入w中。如果w已经实现了WriteString方法，函数会直接调用该方法
if _, err := io.WriteString(&buf, "Hello World"); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}

func exampleCopy() {
// 声明buffer
var buf bytes.Buffer

// 根据字符串创建reader
r := strings.NewReader("some io.Reader stream to be read")

// 将src的数据拷贝到dst，直到在src上到达EOF或发生错误
// 返回拷贝的字节数和遇到的第一个错误
if _, err := io.Copy(&buf, r); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}

func exampleCopayN() {
// 声明buffer
var buf bytes.Buffer

// 根据字符串创建reader
r := strings.NewReader("some io.Reader stream to be read")

// 将src的数据拷贝到dst，直到在src上到达EOF或发生错误
// 返回拷贝的字节数和遇到的第一个错误
if _, err := io.CopyN(&buf, r, 10); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}

func exampleCopyBuffer() {
var buf bytes.Buffer
r1 := strings.NewReader("copy reader")
b := make([]byte, 8)

// 与 Copy 相同，只是它通过提供的缓冲区（如果需要的话）进行分级，而不是分配临时的缓冲区
// 如果buf为nil，则分配一个；否则如果它的长度为零，CopyBuffer将会panic

if _, err := io.CopyBuffer(&buf, r1, b); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}

func exampleReadAtLeast() {
r := strings.NewReader("some io.Reader stream to be read\n")
buf := make([]byte, 10)

// 从r至少读取min字节数据填充进buf
// 返回写入的字节数和错误（如果没有读取足够的字节）
// 只有没有读取到字节时才可能返回EOF；如果读取了有但不够的字节时遇到了EOF，会返回ErrUnexpectedEOF
// ;如果min比buf的长度还大，函数会返回ErrShortBuffer。只有返回值err为nil时，返回值n才会不小于min
if _, err := io.ReadAtLeast(r, buf, 6); err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", buf)
}

func exampleLimitReader() {
r := strings.NewReader("some io.Reader stream to be read\n")
// 返回一个从r中读取了n个字节以EOF停止的Reader
// 返回值接口的底层为*io.LimitedReader类型
lr := io.LimitReader(r, 4)

// 拷贝内容到输出
if _, err := io.Copy(os.Stdout, lr); err != nil {
log.Fatal(err)
}
}

func exampleMultiReader() {
r1 := strings.NewReader("first reader ")
r2 := strings.NewReader("second reader ")
r3 := strings.NewReader("third reader\n")

// 返回一个将提供的Reader在逻辑上串联起来的Reader接口
// 他们依次被读取，当所有的输入流都读取完毕，Read才会返回EOF
// 如果readers中任一个返回了非nil非EOF的错误，Read方法会返回该错误
r := io.MultiReader(r1, r2, r3)
if _, err := io.Copy(os.Stdout, r); err != nil {
log.Fatal(err)
}
}

func exampleTeeReader() {
r := strings.NewReader("some io.Reader stream to be read\n")
var buf bytes.Buffer
// 返回一个将其从r读取的数据写入w的Reader接口
// 所有通过该接口对r的读取都会执行对应的对w的写入
// 没有内部的缓冲：写入必须在读取完成前完成，写入时遇到的任何错误都会作为读取错误返回
tee := io.TeeReader(r, &buf)
if _, err := io.Copy(os.Stdout, tee); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}

func exampleSectionReader() {
r := strings.NewReader("some io.Reader stream to be read\n")

// 返回一个从r中的偏移量off处为起始，读取n个字节后以EOF停止的SectionReader
s := io.NewSectionReader(r, 5, 17)
if _, err := io.Copy(os.Stdout, s); err != nil {
log.Fatal(err)
}
fmt.Println()

// 声明一个长度为6的[]byte
be := make([]byte, 6)

// 从s的第off个字节开始读取内容写入p
if _, err := s.ReadAt(be, 10); err != nil {
log.Fatal(err)
}
fmt.Println(string(be))

// 声明一个长度为6的[]byte
//bs := make([]byte, 6)
// 将s内容填充为从s第10个开始往后的内容
// io.SeekStart 从前面开始往后offset个
// io.SeekEnd   从结尾开始往前-offset个
if _, err := s.Seek(10, io.SeekStart); err != nil {
log.Fatal(err)
}
if _, err := io.Copy(os.Stdout, s); err != nil {
log.Fatal(err)
}
fmt.Println()
}

func exampleMultiWriter() {
r := strings.NewReader("some io.Reader stream to be read\n")

// 声明两个buffer
var buf1, buf2 bytes.Buffer

// 创建一个Writer接口，会将提供给其的数据写入所有创建时提供的Writer接口
w := io.MultiWriter(&buf1, &buf2)

// 拷贝
if _, err := io.Copy(w, r); err != nil {
log.Fatal(err)
}
fmt.Print(buf1.String())
fmt.Print(buf2.String())
}

func examplePipe() {
// 创建一个同步的内存中的管道
// 它可以用于连接期望io.Reader的代码和期望io.Writer的代码
// 一端的读取对应另一端的写入，直接在两端拷贝数据，没有内部缓冲
// 可以安全的并行调用Read和Write或者Read/Write与Close方法
// Close方法会在最后一次阻塞中的I/O操作结束后完成
// 并行调用Read或并行调用Write也是安全的：每一个独立的调用会依次进行
r, w := io.Pipe()
go func() {
w.Write([]byte("some text to be read\n"))
w.Close()
}()
// 初始化一个buffer
buf := new(bytes.Buffer)

// 从reader读取内容
buf.ReadFrom(r)
fmt.Print(buf.String())
}
######################################################################################
D:\go\go\go标准库示例\log\log-syslog.go

package main

import (
"log"
"log/syslog"
)

// syslog 包提供一个简单的系统日志服务的接口

func main() {
// 通过连接到指定网络上的地址来建立到日志守护程序的连接
// 每次写入返回的时候都会发送一条日志消息，其中包含设施和严重性（来自优先级）和标记
// 如果标签为空，则使用 os.Args0。如果网络为空，拨号将连接到本地系统日志服务器。否则，请参阅 net.Dial 的文档以获取网络和 raddr 的有效值
sl, err := syslog.Dial("tcp", "localhost:1234",
syslog.LOG_WARNING|syslog.LOG_DAEMON|syslog.LOG_INFO, "testTag")
if err != nil {
log.Fatal(err)
}
// 写入
if _, err := sl.Write([]byte("Hello World!")); err != nil {
log.Fatal(err)
}

// 关闭连接
if err := sl.Close(); err != nil {
log.Fatal(err)
}

// 建立到系统日志守护进程的新连接
// 每次写入返回的写入程序都会发送一条具有给定优先级（syslog 设施和严重性的组合）和前缀标记的日志消息
// 如果标签为空，则使用 os.Args0
news, err := syslog.New(syslog.LOG_DEBUG, "testNew")
defer news.Close()
if err != nil {
log.Fatal(err)
}

// 创建一个 log.Logger，它的输出以指定的优先级写入系统日志服务
// 这是 syslog 设施和严重性的组合。logFlag 参数是通过 log.New 创建记录器的标志集
l, err := syslog.NewLogger(syslog.LOG_DEBUG, log.Ldate|log.Ltime|log.Lshortfile)
if err != nil {
log.Fatal(err)
}
l.Fatal("退出")
}
######################################################################################
D:\go\go\go标准库示例\log\log.go

package main

import (
"log"
"os"
)

const LogFile = "a.txt"
// log包实现了简单的日志服务

func main() {
// 创建日志文件
file, err := os.Create(LogFile)
if err != nil {
log.Fatal(err)
}

// 创建一个Logger
// 参数out设置日志信息写入的目的地
// 参数prefix会添加到生成的每一条日志前面
// 参数flag定义日志的属性（时间、文件等等）
l := log.New(file, "[INFO]", log.Ldate|log.Ltime|log.Lshortfile)

// 设置logger的输出选项(日志属性)
l.SetFlags(log.Ldate|log.Ltime|log.Lshortfile)

// 设置logger的输出前缀
l.SetPrefix("")

// 设置标准logger的输出目的地，默认是标准错误输出
l.SetOutput(file)

// 写入输出一次日志事件
// 参数s包含在Logger根据选项生成的前缀之后要打印的文本，如果s末尾没有换行会添加换行符
// calldepth用于恢复PC，出于一般性而提供，但目前在所有预定义的路径上它的值都为2
l.Output(2, "Hello World!")

// 返回标准logger的输出前缀
l.Prefix()

// 返回标准logger的输出选项
l.Flags()

l.Println("ok")
// 其它用法大致与fmt包类似
}
######################################################################################
D:\go\go\go标准库示例\math\math-big.go

package main
import "math/big"

// big包实现了大数字的多精度计算
func main() {
exampleInt()
}

func exampleInt() {
// 创建一个值为x的*big.Int
i := big.NewInt(10)

// 返回x的int64表示，如果不能用int64表示，结果为undefined
i.Int64()

// 返回x的uint64表示，如果不能用uint64表示，结果为undefined
i.Uint64()

// 返回x的绝对值的大端在前的字节切片表示
i.Bytes()

// 返回字符串
i.String()

// 返回x的绝对值的字位数，0的字位数为0
i.BitLen()

// 提供了对x的数据不检查而快速的访问，返回构成x的绝对值的小端在前的word切片
// 该切片与x的底层是同一个数组，本函数用于支持在包外实现缺少的低水平功能，否则不应被使用
i.Bits()

// 返回第i个字位的值，即返回(x>>i)&1。i必须不小于0
i.Bit(1)

// 将z设为x并返回z
i.SetInt64(11)

// 将z设为x并返回z
i.SetUint64(11)

// 将buf视为一个大端在前的无符号整数，将z设为该值，并返回z
i.SetBytes([]byte("11"))

// 将z设为s代表的值（base为基数）
// 返回z并用一个bool来表明成功与否。如果失败，z的值是不确定的，但返回值为nil
// 基数必须是0或者2到MaxBase之间的整数。如果基数为0，字符串的前缀决定实际的转换基数："0x"、"0X"表示十六进制；"0b"、"0B"表示二进制；"0"表示八进制；否则为十进制
i.SetString("11", big.MaxBase)
}
######################################################################################
D:\go\go\go标准库示例\math\math-rand.go

package main
import (
"fmt"
"math/rand"
"os"
"text/tabwriter"
"time"
)
// rand包实现了伪随机数生成器

func main() {
// 全局随机数
example()

// 自定随机数
exampleRand()

// 切片值随机排序
exampleShuffle()
}

func example() {
// 使用给定的seed来初始化生成器到一个确定的状态
// 如未调用，默认资源的行为就好像调用了Seed(1)
// 如果需要实现随机数，seed值建议为 时间戳
// 如果seed给定固定值，结果永远相同
rand.Seed(time.Now().UnixNano())

// 返回一个非负的伪随机int值
fmt.Println(rand.Int())

// 返回一个取值范围在[0,n]的伪随机int值，如果n<=0会panic
fmt.Println(rand.Intn(100))

// 返回一个int32类型的非负的31位伪随机数
fmt.Println(rand.Int31())

// 返回一个取值范围在[0,n]的伪随机int32值，如果n<=0会panic
fmt.Println(rand.Int31n(100))

// 返回一个int64类型的非负的63位伪随机数
fmt.Println(rand.Int63())

// 返回一个取值范围在[0, n]的伪随机int64值，如果n<=0会panic
fmt.Println(rand.Int63n(100))

// 返回一个uint32类型的非负的32位伪随机数
fmt.Println(rand.Uint32())

// 返回一个uint64类型的非负的64位伪随机数
fmt.Println(rand.Uint64())

// 返回一个取值范围在[0, 1]的伪随机float32值
fmt.Println(rand.Float32())

// 返回一个取值范围在[0, 1]的伪随机float64值
fmt.Println(rand.Float64())

// 返回一个服从标准正态分布（标准差=1，期望=0）、取值范围在[-math.MaxFloat64, +math.MaxFloat64]的float64值
fmt.Println(rand.NormFloat64())

// 返回一个服从标准指数分布（率参数=1，率参数是期望的倒数）、取值范围在(0, +math.MaxFloat64]的float64值
fmt.Println(rand.ExpFloat64())

// 返回一个有n个元素的，[0,n)范围内整数的伪随机排列的切片
fmt.Println(rand.Perm(15))
}

func exampleRand() {
// 初始化一个Source，代表一个生成均匀分布在范围[0, 1<<63)的int64值的（伪随机的）资源
// 需要随机，建议使用时间戳，详情查看example()
source := rand.NewSource(99)

// 初始化*rand.Rand
r := rand.New(source)

// 初始化一个过滤器
w := tabwriter.NewWriter(os.Stdout, 1, 1, 1, ' ', 0)
defer w.Flush()
show := func(name string, v1, v2, v3 interface{}) {
fmt.Fprintf(w, "%s\t%v\t%v\t%v\n", name, v1, v2, v3)
}

show("Float32", r.Float32(), r.Float32(), r.Float32())
show("Float64", r.Float64(), r.Float64(), r.Float64())
show("ExpFloat64", r.ExpFloat64(), r.ExpFloat64(), r.ExpFloat64())
show("NormFloat64", r.NormFloat64(), r.NormFloat64(), r.NormFloat64())
show("Int31", r.Int31(), r.Int31(), r.Int31())
show("Int63", r.Int63(), r.Int63(), r.Int63())
show("Uint32", r.Uint32(), r.Uint32(), r.Uint32())
show("Intn(10)", r.Intn(10), r.Intn(10), r.Intn(10))
show("Int31n(10)", r.Int31n(10), r.Int31n(10), r.Int31n(10))
show("Int63n(10)", r.Int63n(10), r.Int63n(10), r.Int63n(10))
show("Perm", r.Perm(5), r.Perm(5), r.Perm(5))
}

func exampleShuffle() {
numbers := []byte("12345")
letters := []byte("ABCDE")

// 随机交换数切片的位置, n应为切片的长度，n < 0 会panic
rand.Shuffle(len(numbers), func(i, j int) {
numbers[i], numbers[j] = numbers[j], numbers[i]
letters[i], letters[j] = letters[j], letters[i]
})
for i := range numbers {
fmt.Printf("%c: %c\n", letters[i], numbers[i])
}
}
######################################################################################
D:\go\go\go标准库示例\math\math.go

package main
import (
"math"
)

// math包提供了基本的数学常数和数学函数
func main() {

// 返回一个NaN, IEEE 754“这不是一个数字”值
math.NaN()

// 判断f是否表示一个NaN（Not A Number）值
math.IsNaN(12.34)

// 如果sign>=0函数返回正无穷大，否则返回负无穷大
f := math.Inf(0)

// 如果sign > 0，f是正无穷大时返回真；如果sign<0，f是负无穷大时返回真；sign==0则f是两种无穷大时都返回真
math.IsInf(12.34, 1)
math.IsInf(f, 0)

// 返回浮点数f的IEEE 754格式二进制表示对应的4字节无符号整数
// float32转uint32
u32 := math.Float32bits(12.34)

// 返回无符号整数b对应的IEEE 754格式二进制表示的4字节浮点数
// uint32转float32
math.Float32frombits(u32)

// 返回浮点数f的IEEE 754格式二进制表示对应的8字节无符号整数
// float64转uint64
u64 := math.Float64bits(12.34)

// 返回无符号整数b对应的IEEE 754格式二进制表示的8字节浮点数
// uint64转float64
math.Float64frombits(u64)

// 如果x是一个负数或者负零，返回真
// 判断是否小于0
math.Signbit(-1)

// 返回x的绝对值与y的正负号的浮点数
math.Copysign(-12.34, -22.54) // -12.34

// 返回不小于x的最小整数（的浮点值）
// 计算数字只入不舍
math.Ceil(12.34)

// 返回不大于x的最小整数（的浮点值）
// 计算数字只舍不入
math.Floor(12.34)

// 四舍五入
math.Round(12.34)

// 返回x的整数部分（的浮点值）
math.Trunc(12.34)

// 返回f的整数部分和小数部分，结果的正负号都相同
math.Modf(12.34)

// 参数x到参数y的方向上，下一个可表示的数值；如果x==y将返回x
math.Nextafter(12.34, 15.67)

// 同Nextafter类似
math.Nextafter32(12.34, 15.67)

// 返回x的绝对值
math.Abs(-12.34) // 12.34

// 返回x和y中最大值
math.Max(12.3, 22)

// 返回x和y中最小值
math.Min(12.3, 22)

// 返回x-y和0中的最大值
math.Dim(12.3, 12)

// 取余运算，可以理解为 x-Trunc(x/y)*y，结果的正负号和x相同
math.Mod(22, 3)

// IEEE 754差数求值，即x减去最接近x/y的整数值（如果有两个整数与x/y距离相同，则取其中的偶数）与y的乘积
math.Remainder(12, 34)

// 返回x的二次方根
math.Sqrt(144) // 12

// 返回x的三次方根
math.Cbrt(27)

// 返回Sqrt(p*p + q*q)，注意要避免不必要的溢出或下溢
math.Hypot(2, 3)

// 求正弦
math.Sin(3)

// 求余弦
math.Cos(4)

// 求正切
math.Tan(5)

// 函数返回Sin(x), Cos(x)
math.Sincos(3)

// 求反正弦（x是弧度）
// Asin(±0) = ±0
// Asin(x) = NaN if x < -1 or x > 1
math.Asin(0.5)

// 求反余弦（x是弧度）
// Acos(x) = NaN if x < -1 or x > 1
math.Acos(0.5)

// 求反正切（x是弧度）
// Atan(±0) = ±0
// Atan(±Inf) = ±Pi/2
math.Atan(0.5)

// 类似Atan(y/x)，但会根据x，y的正负号确定象限
math.Atan2(0.5, 0.2)

// 求双曲正弦
math.Sinh(2)

// 求双曲余弦
math.Cosh(2)

// 求双曲正切
math.Tanh(2)

// 求反双曲正弦
math.Asinh(2)

// 求反双曲余弦
math.Acosh(2)

// 求反双曲正切
math.Atanh(2)

// 求自然对数
math.Log(2)

// 等价于Log(1+x)。但是在x接近0时，本函数更加精确
math.Log(0.0001)

// 求2为底的对数；特例和Log相同
math.Log2(2)

// 求10为底的对数；特例和Log相同
math.Log10(10)

// 返回x的二进制指数值，可以理解为Trunc(Log2(x))
math.Logb(10)

// 类似Logb，但返回值是整型
math.Ilogb(12.34)

// 返回一个标准化小数frac和2的整型指数exp，满足f == frac * 2**exp，且0.5 <= Abs(frac) < 1
frac, exp := math.Frexp(12.34)

// Frexp的反函数，返回 frac * 2**exp
math.Ldexp(frac, exp)

// 返回E**x；x绝对值很大时可能会溢出为0或者+Inf，x绝对值很小时可能会下溢为1
math.Exp(12)

// 等价于Exp(x)-1，但是在x接近零时更精确；x绝对值很大时可能会溢出为-1或+Inf
math.Expm1(12)

// 返回2**x
math.Exp2(12)

// 返回x**y
math.Pow(3, 4)

// 返回10**e
math.Pow10(2)

// 伽玛函数（当x为正整数时，值为(x-1)!）
math.Gamma(10)

// 返回Gamma(x)的自然对数和正负号
math.Lgamma(10)

// 误差函数
math.Erf(10.01)

// 余补误差函数
math.Erfc(10.01)

// 第一类贝塞尔函数，0阶
math.J0(2)

// 第一类贝塞尔函数，1阶
math.J1(2)

// 第一类贝塞尔函数，n阶
math.Jn(2, 2)

// 第二类贝塞尔函数，0阶
math.Y0(2)

// 第二类贝塞尔函数，1阶
math.Y1(2)

// 第二类贝塞尔函数，n阶
math.Yn(2, 2)
}
######################################################################################
D:\go\go\go标准库示例\mime\mime.go

package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"mime"
"mime/multipart"
"mime/quotedprintable"
"net/mail"
"strings"
)

// mime实现了MIME的部分规定
func main() {
// 解析multipart内容，适用于HTTP和常见浏览器生成的multipart主体
exampleMultipart()

// 读/写multipart内容
exampleMultipartRW()

// quoted-printable编码/解码
exampleQuotedprintable()

//RFC2047编码字
exampleWord()
}

func exampleWord() {
// 初始化一个RFC2047编码字编码器
e := mime.WordEncoder('q')

// 编码
// 如果s是没有特殊字符的ASCII码，返回原始字符串
// 提供的字符集是s的IANA字符集名称不区分大小写
str := e.Encode("utf-8", "¡Hola, señor!")
fmt.Println(str)
fmt.Println(e.Encode("utf-8", "Hello World!"))

// 解码包含RFC 2047编码字的MIME头
d := new(mime.WordDecoder)

// 解码
s, err := d.Decode(str)
if err != nil {
log.Fatal(err)
}
fmt.Println(s)
}

func exampleMultipart() {
// 声明邮件信息
msg := &mail.Message{
Header: map[string][]string{
"Content-Type": {"multipart/mixed; boundary=foo"},
},
Body: strings.NewReader(
"--foo\r\nFoo: one\r\n\r\nA section\r\n" +
"--foo\r\nFoo: two\r\n\r\nAnd another\r\n" +
"--foo--\r\n"),
}

// 解析Content-Type
// 解析一个媒体类型值以及可能的参数
// 媒体类型值一般应为Content-Type和Conten-Disposition头域的值
// 成功的调用会返回小写字母、去空格的媒体类型和一个非空的map。返回的map映射小写字母的属性和对应的属性值
mediaType, params, err := mime.ParseMediaType(msg.Header.Get("Content-Type"))
if err != nil {
log.Fatal(err)
}

// 判断字符串是否有指定前缀
if strings.HasPrefix(mediaType, "multipart/") {

// 使用给出的MIME边界和reader创建一个新的reader
// 例如：边界boundary值为foo，会使用foo解析传入的reader内容
mr := multipart.NewReader(msg.Body, params["boundary"])
for {

// 返回multipart的下一个记录或者返回错误。如果没有更多记录会返回io.EOF
p, err := mr.NextPart()
if err == io.EOF {

return

}
if err != nil {
log.Fatal(err)
}

// 读取内容
slurp, err := ioutil.ReadAll(p)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Part %q: %q\n", p.Header.Get("Foo"), slurp)
}
}
}

func exampleMultipartRW() {
var buf bytes.Buffer

// 初始化一个随机边界的writer
w := multipart.NewWriter(&buf)

// 查看边界
fmt.Println(w.Boundary())

// 设置边界
// 必须在创建任何记录之前调用，boundary只能包含特定的ascii字符，并且长度应在1-69字节之间
if err := w.SetBoundary("testing"); err != nil {
log.Fatal(err)
}
fmt.Println(w.Boundary())

// 查看对应的HTTP multipart请求的Content-Type的值，多以multipart/form-data起始
fmt.Println(w.FormDataContentType())

// 使用给出的属性名调用CreatePart方法
wt, err := w.CreateFormField("test")
if err != nil {
log.Fatal(err)
}

// 写入test
if _, err := wt.Write([]byte("Hello World!")); err != nil {
log.Fatal(err)
}

// 关闭
if err := w.Close(); err != nil {
log.Fatal(err)
}

// 根据指定边界创建reader
r := multipart.NewReader(&buf, "testing")
for {

// 返回multipart的下一个记录或者返回错误。如果没有更多记录会返回io.EOF
p, err := r.NextPart()
if err == io.EOF {

return

}
if err != nil {
log.Fatal(err)
}

// 读取内容
b, err := ioutil.ReadAll(p)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
}

func exampleQuotedprintable() {

// 声明buffer
var buf bytes.Buffer

// 初始化一个writer
w := quotedprintable.NewWriter(&buf)

// 写入，行长限制为76个字符。编码字节不必刷新，直到Writer关闭
if _, err := w.Write([]byte("Hello, Gophers! = \t")); err != nil {
log.Fatal(err)
}

// 关闭
if err := w.Close(); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())

// 初始化一个reader
r := quotedprintable.NewReader(&buf)

// 读取内容
b, err := ioutil.ReadAll(r)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
######################################################################################
D:\go\go\go标准库示例\net\net-http-cgi.go

package main
import (
"log"
"net/http"
"net/http/cgi"
)

// cgi包实现了CGI（通用网关接口）
// 请注意，使用CGI意味着启动一个新的进程来处理每个请求，这通常比使用长时间运行的服务器效率低
// 此软件包主要用于与现有系统兼容
// CGI(Common Gateway Interface)是能让web服务器和CGI脚本共同处理客户的请求的协议。它的协议定义文档是http://www.ietf.org/rfc/rfc3875
// 其中Web服务器负责管理连接，数据传输，网络交互等。至于CGI脚本就负责管理具体的业务逻辑
// Web服务器的功能是将客户端请求（HTTP Request）转换成CGI脚本请求，然后执行脚本，接着将CGI脚本回复转换为客户端的回复（HTTP Response）

func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

// 初始化一个cgi.Handler，用于在子进程中执行具有一个CGI环境的可执行程序
handler := new(cgi.Handler)

// 设置CGI可执行文件的路径
handler.Path = "/usr/local/opt/go/libexec/bin/go"

// Dir指定CGI程序的工作目录
// 如果Dir为""则使用Path的基目录；如果Path没有基目录则使用当前工作目录
handler.Dir = "/Users/zc/go/project/standard-library/"

// 指定文件路径
script := "testdata/cgi/" + r.URL.Path

// 设置进程参数
args := []string{"run", script}

// 可选的传递给子进程的参数
handler.Args = append(handler.Args, args...)

// 额外设置的环境变量（如果有），格式为"key=value"
handler.Env = append(handler.Env, "GOPATH=/Users/zc/go", "GOROOT=/usr/local/opt/go/libexec")

// 从host继承的环境变量，只有"key"
handler.InheritEnv = []string{"HOME", "GOCACHE"}

// 可选的logger接口切片，如为nil则使用log.Print
handler.Logger = nil

// handler的根URI前缀，""代表"/"
handler.Root = ""
handler.ServeHTTP(w, r)
})

if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\net\net-http-fcgi.go

package main
import (
"fmt"
"log"
"net"
"net/http"
"net/http/fcgi"
)

// fcgi包实现了FastCGI协议。目前只支持响应器的角色。
// 协议定义的地址：http://www.fastcgi.com/drupal/node/6?q=node/22
func main() {
// 服务监听
listener, err:= net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}

// 初始化一个自定义handler
srv := new(FastCGIHandler)

// 接受从监视器l传入的FastCGI连接，为每一个FastCGI连接创建一个新的go程，该go程读取请求然后调用handler回复请求
// 如果l是nil，Serve将从os.Stdin接受连接
// 如果handler是nil，将使用http.DefaultServeMux
if err := fcgi.Serve(listener, srv); err != nil {
log.Fatal(err)
}
}

type FastCGIHandler struct{}
func (s FastCGIHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) {
fmt.Println(123)
resp.Write([]byte("<h1>Hello, World!</h1>\n<p>Hello Gopher.</p>"))
}

/*
   	需要nginx配置fastcgi
   	server {
           listen 80;
           server_name go.dev;
           root /root/go/src/godev;
           index index.html;
           #gzip off;
           #proxy_buffering off;
           location / {
                    try_files $uri $uri/;
           }

           location ~ /.* {
                   include         fastcgi.conf;
                   fastcgi_pass    127.0.0.1:8081;
           }
           try_files $uri $uri.html =404;
   	}
*/
######################################################################################
D:\go\go\go标准库示例\net\net-http-httptrace.go

package main
import (
"fmt"
"log"
"net/http"
"net/http/httptrace"
)

// httptrace包提供跟踪HTTP客户端请求中的事件的机制
// http钩子
func main() {
// 创建GET请求
req, _ := http.NewRequest("GET", "http://example.com", nil)

// 声明一组挂钩
// 可以在传出的HTTP请求的各个阶段运行，任何特定的钩子可能是零
// 函数可以从不同的goroutine同时调用，有些可能在请求完成或失败后调用
trace := &httptrace.ClientTrace{

// 在成功连接后调用
// 没有用于连接失败的钩子；相反，使用transport.roundtrip中的错误
GotConn: func(connInfo httptrace.GotConnInfo) {
fmt.Printf("Got Conn: %+v\n", connInfo)
},

// 在DNS查找结束时调用
DNSDone: func(dnsInfo httptrace.DNSDoneInfo) {
fmt.Printf("DNS Info: %+v\n", dnsInfo)
},
}

// 根据提供的ctx返回一个新的Context
// 除了使用ctx注册的任何以前的挂钩外，使用返回的Context创建的HTTP客户端请求将使用提供的跟踪挂钩。在提供的轨迹中定义的任何钩子将首先被调用
ctx := httptrace.WithClientTrace(req.Context(), trace)

// 修改r中的Context并返回一个浅表副本
// ctx不能为nil
// 对于传出客户端请求，上下文控制请求及其响应的整个生命周期：获取连接，发送请求以及读取响应头和正文
req = req.WithContext(ctx)

_, err := http.DefaultTransport.RoundTrip(req)
if err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\net\net-http-pprof.go

package main
import (
"log"
"net/http"
_ "net/http/pprof"
)

// pprof包通过它的HTTP服务端提供pprof可视化工具期望格式的运行时剖面文件数据服务
// 本包一般只需导入获取其注册HTTP处理器的副作用。处理器的路径以/debug/pprof/开始
func main() {
// 启动服务
log.Println(http.ListenAndServe("localhost:6060", nil))

/*
	使用pprof工具查看堆剖面
	go tool pprof http://localhost:6060/debug/pprof/heap

	查看周期30秒的CPU剖面
	go tool pprof http://localhost:6060/debug/pprof/profile

	查看go程阻塞剖面
	go tool pprof http://localhost:6060/debug/pprof/block

	浏览器可直接访问http://localhost:6060/debug/pprof/查看所有信息
*/
}
######################################################################################
D:\go\go\go标准库示例\net\net-http.go

package main
import (
"bytes"
"context"
"crypto/tls"
"fmt"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/url"
"strings"
"time"
)

// http包提供了HTTP客户端和服务端的实现
func main() {
// 指定func注册hander到DefaultServeMux(包含Hijacker接口用法)
exampleHandleFunc()

// 注册handler到DefaultServeMux
exampleHandler()

// Request对象示例
exampleRequest()

// Response对象示例
exampleResponse()

// http curl示例
exampleHttp()

// 客户端请求
exampleClient()

// 静态文件服务监听
exampleFileServer()

// 使用ServeMux创建服务
exampleServeMux()

// 服务端创建
exampleServer()

// 服务器监听返回html内容
exampleServerHtml()

// transport代理
exampleTransport()
}

type CustomHandler struct{}
func (CustomHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// 限制Body的大小
r.Body = http.MaxBytesReader(w, r.Body, 10485760) // 10M
if r.Method == "GET" {
w.Write([]byte("Hello World!"))
} else {
http.Error(w, "404 page not found", http.StatusNotFound)
}
return
}

func exampleHandler() {
// 返回一个简单的请求处理器，该处理器会对每个请求都回复"404 page not found"
notFound := http.NotFoundHandler()

// 返回一个请求处理器，该处理器会对每个请求都使用状态码code重定向到网址url
redirect := http.RedirectHandler("http://www.baidu.com", http.StatusFound)

// 返回一个采用指定时间限制的请求处理器
// 返回的Handler会调用h.ServeHTTP去处理每个请求，但如果某一次调用耗时超过了时间限制，该处理器会回复请求状态码503 Service Unavailable，并将msg作为回复的主体（如果msg为空字符串，将发送一个合理的默认信息）
// 在超时后，h对它的ResponseWriter接口参数的写入操作会返回ErrHandlerTimeout
timeout := http.TimeoutHandler(redirect, time.Minute*2, "")

// 返回一个处理器，该处理器会将请求的URL.Path字段中给定前缀prefix去除后再交由h处理
// StripPrefix会向URL.Path字段中没有给定前缀的请求回复404 page not found
stripPrefix := http.StripPrefix("/temp/", redirect)

// 自定义handler
custom := CustomHandler{}

// 注册HTTP处理器handler和对应的模式pattern（注册到DefaultServeMux）
// 如果该模式已经注册有一个处理器，Handle会panic
http.Handle("/404", notFound)
http.Handle("/redirect", redirect)
http.Handle("/timeout", timeout)
http.Handle("/stripPrefix", stripPrefix)
http.Handle("/custom", custom)
}

func exampleHandleFunc() {
// 注册一个处理器函数handler和对应的模式pattern（注册到DefaultServeMux）
http.HandleFunc("/hijack", func(w http.ResponseWriter, r *http.Request) {
// 指定Hijacker接口
// HTTP处理器ResponseWriter接口参数的下层如果实现了Hijacker接口，可以让HTTP处理器接管该连接
hj, ok := w.(http.Hijacker)
if !ok {
http.Error(w, "webserver doesn't support hijacking", http.StatusInternalServerError)
return
}

// Hijack让调用者接管连接，返回连接和关联到该连接的一个缓冲读写器
// 调用本方法后，HTTP服务端将不再对连接进行任何操作
// 调用者有责任管理、关闭返回的连接
conn, buf, err := hj.Hijack()
if err != nil {

// 用指定的错误信息和状态码回复请求，将数据写入w。错误信息必须是明文
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

// 关闭连接
defer conn.Close()

// 写入
if _, err := buf.WriteString("Now we're speaking raw TCP. Say hi: "); err != nil {
log.Printf("error write string: %v", err)
return
}

// 将所有缓冲数据写入
if err := buf.Flush(); err != nil {
log.Printf("error flush: %v", err)
return
}

// 读取直到输入中第一次出现delim，返回一个包含分隔符之前的数据的字符串
// 如果在查找分隔符之前遇到错误，则返回错误之前读取的数据和错误本身（通常为io.EOF）
s, err := buf.ReadString('\n')
if err != nil {
log.Printf("error reading string: %v", err)
return
}
fmt.Fprintf(buf, "You said: %q\nBye.\n", s)
if err := buf.Flush(); err != nil {
log.Printf("error flush: %v", err)
return
}
})
}

func exampleRequest() {
body := "a=1&b=2&c=3"

// 解析url
urls, err := url.Parse("http://www.google.com/robots.txt")
if err != nil {
log.Fatal(err)
}

// body转io.ReaderCloser
rc := func(reader io.Reader) io.ReadCloser {
rcr, ok := reader.(io.ReadCloser)
if !ok && reader != nil {
rcr = ioutil.NopCloser(reader)
}
return rcr
}(strings.NewReader(body))
req := &http.Request{

//  Method指定HTTP方法（GET、POST、PUT等）。对客户端，""代表GET
Method: "GET",

// URL在服务端表示被请求的URI，在客户端表示要访问的URL。
// 在服务端，URL字段是解析请求行的URI（保存在RequestURI字段）得到的，
// 对大多数请求来说，除了Path和RawQuery之外的字段都是空字符串
// 在客户端，URL的Host字段指定了要连接的服务器，而Request的Host字段（可选地）指定要发送的HTTP请求的Host头的值
URL: urls,

// 接收到的请求的协议版本。本包生产的Request总是使用HTTP/1.1
Proto:      "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,

/*
	Header字段用来表示HTTP请求的头域。如果头域（多行键值对格式）为：
		accept-encoding: gzip, deflate
		Accept-Language: en-us
		Connection: keep-alive
	则：
		Header = map[string][]string{
			"Accept-Encoding": {"gzip, deflate"},
			"Accept-Language": {"en-us"},
			"Connection": {"keep-alive"},
		}
	HTTP规定头域的键名（头名）是大小写敏感的，请求的解析器通过规范化头域的键名来实现这点。
	在客户端的请求，可能会被自动添加或重写Header中的特定的头，参见Request.Write方法
*/

Header: make(http.Header),

// Body是请求的主体
// 在客户端，如果Body是nil表示该请求没有主体，相当于GET请求
// Client的Transport字段会负责调用Body的Close方法。
// 在服务端，Body字段总是非nil的；但在没有主体时，读取Body会立刻返回EOF。
// Server会关闭请求的主体，ServeHTTP处理器不需要关闭Body字段
Body: rc,

// 定义一个可选的func以返回body的新副本，使用GetBody仍然需要设置body
// 当重定向需要多次读取主体时，它用于客户端请求
GetBody: func() (closer io.ReadCloser, e error) {
return rc, nil
},

// ContentLength记录相关内容的长度。
// 如果为-1，表示长度未知，如果>=0，表示可以从Body字段读取ContentLength字节数据
// 在客户端，如果Body非nil而该字段为0，表示不知道Body的长度
ContentLength: 0,

// Close在服务端指定是否在回复请求后关闭连接，在客户端指定是否在发送请求后关闭连接
Close: false,

// 在服务端，Host指定URL会在其上寻找资源的主机
// 该值可以是Host头的值，或者URL自身提供的主机名
// Host的格式可以是"host:port"
// 在客户端，请求的Host字段（可选地）用来重写请求的Host头
// 如过该字段为""，Request.Write方法会使用URL字段的Host
Host: urls.Host,

// Form是解析好的表单数据，包括URL字段的query参数和POST或PUT的表单数据
// 本字段只有在调用ParseForm后才有效
// 在客户端，会忽略请求中的本字段而使用Body替代
Form: nil,

// PostForm是解析好的POST或PUT的表单数据
// 本字段只有在调用ParseForm后才有效
// 在客户端，会忽略请求中的本字段而使用Body替代
PostForm: nil,

// MultipartForm是解析好的多部件表单，包括上传的文件
// 本字段只有在调用ParseMultipartForm后才有效
// 在客户端，会忽略请求中的本字段而使用Body替代
MultipartForm: nil,

// RemoteAddr允许HTTP服务器和其他软件记录该请求的来源地址，一般用于日志
// 本字段不是ReadRequest函数填写的，也没有定义格式
// 本包的HTTP服务器会在调用处理器之前设置RemoteAddr为"IP:port"格式的地址
// 客户端会忽略请求中的RemoteAddr字段
RemoteAddr: "",

// RequestURI是被客户端发送到服务端的请求的请求行中未修改的请求URI
// 一般应使用URI字段，在客户端设置请求的本字段会导致错误
RequestURI: "",

// TLS字段允许HTTP服务器和其他软件记录接收到该请求的TLS连接的信息
// 本字段不是ReadRequest函数填写的
// 对启用了TLS的连接，本包的HTTP服务器会在调用处理器之前设置TLS字段，否则将设TLS为nil。
// 客户端会忽略请求中的TLS字段
TLS: nil,
}

// 判断该请求使用的HTTP协议版本至少是major.minor
req.ProtoAtLeast(1, 1)

// 返回请求中的客户端用户代理信息（请求的User-Agent头）
req.UserAgent()

// 返回请求中的访问来路信息。（请求的Referer头）
// Referer在请求中就是拼错了的，这是HTTP早期就有的错误
// 该值也可以从用Header["Referer"]获取；让获取Referer字段变成方法的好处是，编译器可以诊断使用正确单词拼法的req.Referrer()的程序，但却不能诊断使用Header["Referrer"]的程序
req.Referer()

// 向请求中添加一个cookie
// 所有的cookie都写在同一行，用分号分隔（cookie内部用逗号分隔属性）
req.AddCookie(&http.Cookie{
Name:  "GoSession",
Value: "dasghdjashfjgasidhqwi321u34h12bdusag",
})

// 使用提供的用户名和密码，采用HTTP基本认证，设置请求的Authorization头。HTTP基本认证会明码传送用户名和密码
req.SetBasicAuth("gopher", "123123")
var buf bytes.Buffer

// 以有线格式将HTTP/1.1请求写入w（用于将请求写入下层TCPConn等）
// 本方法会考虑请求的如下字段：Host、URL、Method (defaults to "GET")、Header、ContentLength、TransferEncoding、Body
// 如果存在Body，ContentLength字段<= 0且TransferEncoding字段未显式设置为["identity"]，Write方法会显式添加"Transfer-Encoding: chunked"到请求的头域。Body字段会在发送完请求后关闭
req.Write(&buf)
buf.Reset()

// 类似Write但会将请求以HTTP代理期望的格式发送
// 会使用绝对URI（包括协议和主机名）来初始化请求的第1行（Request-URI行）。无论何种情况，WriteProxy都会使用r.Host或r.URL.Host设置Host头
req.WriteProxy(&buf)

// 解析并返回该请求的Cookie头设置的cookie
req.Cookies()

// 返回请求中名为name的cookie，如果未找到该cookie会返回nil, ErrNoCookie
req.Cookie("GoSession")

// 解析URL中的查询字符串，并将解析结果更新到r.Form字段
// 对于POST或PUT请求，ParseForm还会将body当作表单解析，并将结果既更新到r.PostForm也更新到r.Form
// 解析结果中，POST或PUT请求主体要优先于URL查询字符串（同名变量，主体的值在查询字符串的值前面）
// 如果请求的主体的大小没有被MaxBytesReader函数设定限制，其大小默认限制为开头10MB
// ParseMultipartForm会自动调用ParseForm。重复调用本方法是无意义的
req.ParseForm()

// 将请求的主体作为multipart/form-data解析
// 请求的整个主体都会被解析，得到的文件记录最多maxMemery字节保存在内存，其余部分保存在硬盘的temp文件里
// 如果必要，ParseMultipartForm会自行调用ParseForm。重复调用本方法是无意义的
req.ParseMultipartForm(10485760) // 10M

// 返回key为键查询r.Form字段得到结果[]string切片的第一个值
// POST和PUT主体中的同名参数优先于URL查询字符串
// 如果必要，本函数会隐式调用ParseMultipartForm和ParseForm
req.FormValue("a")

// 返回key为键查询r.PostForm字段得到结果[]string切片的第一个值
// 如果必要，本函数会隐式调用ParseMultipartForm和ParseForm
req.PostFormValue("a")

// 返回以key为键查询r.MultipartForm字段得到结果中的第一个文件和它的信息
// 如果必要，本函数会隐式调用ParseMultipartForm和ParseForm。查询失败会返回ErrMissingFile错误
req.FormFile("b")

// 如果请求是multipart/form-data POST请求，MultipartReader返回一个multipart.Reader接口，否则返回nil和一个错误
// 使用本函数代替ParseMultipartForm，可以将r.Body作为流处理
req.MultipartReader()
}

func exampleResponse() {
resp := &http.Response{
// 响应状态，例如"200 OK"
Status: "200 OK",

// 响应状态码，例如200
StatusCode: http.StatusOK,

// 协议版本
Proto:      "HTTP/1.0",
ProtoMajor: 1,
ProtoMinor: 1,

// Header保管头域的键值对。
// 如果回复中有多个头的键相同，Header中保存为该键对应用逗号分隔串联起来的这些头的值
// 被本结构体中的其他字段复制保管的头（如ContentLength）会从Header中删掉
// Header中的键都是规范化的，参见CanonicalHeaderKey函数
Header: make(http.Header),

// Body代表回复的主体
// Client类型和Transport类型会保证Body字段总是非nil的，即使回复没有主体或主体长度为0
// 关闭主体是调用者的责任
// 如果服务端采用"chunked"传输编码发送的回复，Body字段会自动进行解码
Body: nil,

// ContentLength记录相关内容的长度
// 其值为-1表示长度未知（采用chunked传输编码）
// 除非对应的Request.Method是"HEAD"，否则其值>=0表示可以从Body读取的字节数
ContentLength: -1,

// Close记录头域是否指定应在读取完主体后关闭连接。（即Connection头）
// 该值是给客户端的建议，Response.Write方法的ReadResponse函数都不会关闭连接
Close: false,

// Trailer字段保存和头域相同格式的trailer键值对，和Header字段相同类型
Trailer: make(http.Header),

// Request是用来获取此回复的请求
// Request的Body字段是nil（因为已经被用掉了）
// 这个字段是被Client类型发出请求并获得回复后填充的
Request: nil,

// TLS包含接收到该回复的TLS连接的信息。 对未加密的回复，本字段为nil
// 返回的指针是被（同一TLS连接接收到的）回复共享的，不应被修改
TLS: nil,
}

// 判断该回复使用的HTTP协议版本至少是major.minor
resp.ProtoAtLeast(1, 1)

// 解析并返回该回复中的Set-Cookie头设置的cookie
resp.Cookies()

// 返回该回复的Location头设置的URL
// 相对地址的重定向会相对于该回复对应的请求来确定绝对地址
// 如果回复中没有Location头，会返回nil, ErrNoLocation
resp.Location()

var buf bytes.Buffer
// 以有线格式将回复写入w（用于将回复写入下层TCPConn等）
// 本方法会考虑如下字段：StatusCode、ProtoMajor、ProtoMinor、Request.Method、TransferEncoding、Trailer、Body、ContentLength、Header（不规范的键名和它对应的值会导致不可预知的行为）
// Body字段在发送完回复后会被关闭
resp.Write(&buf)
}

func exampleHttp() {
var uri = "http://www.google.com/robots.txt"
var body = "a=1&b=2&c=3"
values, _ := url.ParseQuery(body)

// GET请求
http.Get(uri)

// POST请求，可指定ContentType
http.Post(uri, "application/x-www-form-urlencoded", strings.NewReader(body))

// POST请求，默认使用application/x-www-form-urlencoded
http.PostForm(uri, values)

// Head请求
http.Head(uri)
}

func exampleClient() {
body := "a=1&b=2&c=3"

// 使用指定的方法、网址和可选的主题创建并返回一个新的*http.Request请求
// 如果body参数实现了io.Closer接口，Request返回值的Body 字段会被设置为body，并会被Client类型的Do、Post和PostFOrm方法以及Transport.RoundTrip方法关闭
// 可以直接使用http.Request
req, err := http.NewRequest("GET", "http://www.google.com/robots.txt", strings.NewReader(body))
if err != nil {
log.Fatal(err)
}

// 初始化http客户端
// 等于直接使用&http.Client{}
client := http.DefaultClient
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
}

// 关闭body
defer resp.Body.Close()

// 读取body内容
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s\n", b)
}

func exampleFileServer() {
// 指定目录。空Dir被视为"."，即代表当前目录
dir := http.Dir("/tmp")

// 返回一个使用FileSystem接口root提供文件访问服务的HTTP处理器
fileServer := http.FileServer(dir)

// 返回一个处理器，该处理器会将请求的URL.Path字段中给定前缀prefix去除后再交由h处理
// StripPrefix会向URL.Path字段中没有给定前缀的请求回复404 page not found
fileHandler := http.StripPrefix("/tmpfiles/", fileServer)

// 注册HTTP处理器handler和对应的模式pattern（注册到DefaultServeMux）
// 如果该模式已经注册有一个处理器，Handle会panic
http.Handle("/tmpfiles/", fileHandler)

// 监听TCP地址addr，并且会使用handler参数调用Serve函数处理接收到的连接
// handler参数一般会设为nil，此时会使用DefaultServeMux
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}

func exampleServeMux() {
// 创建并返回一个新的*http.ServeMux
// ServeMux类型是HTTP请求的多路转接器。它会将每一个接收的请求的URL与一个注册模式的列表进行匹配，并调用和URL最匹配的模式的处理器
// 模式是固定的、由根开始的路径，如"/favicon.ico"，或由根开始的子树，如"/images/"（注意结尾的斜杠）。较长的模式优先于较短的模式，因此如果模式"/images/"和"/images/thumbnails/"都注册了处理器，后一个处理器会用于路径以"/images/thumbnails/"开始的请求，前一个处理器会接收到其余的路径在"/images/"子树下的请求
// 注意，因为以斜杠结尾的模式代表一个由根开始的子树，模式"/"会匹配所有的未被其他注册的模式匹配的路径，而不仅仅是路径"/"
// 模式也能（可选地）以主机名开始，表示只匹配该主机上的路径。指定主机的模式优先于一般的模式，因此一个注册了两个模式"/codesearch"和"codesearch.google.com/"的处理器不会接管目标为"http://www.google.com/"的请求。
// ServeMux还会注意到请求的URL路径的无害化，将任何路径中包含"."或".."元素的请求重定向到等价的没有这两种元素的URL
mux := http.NewServeMux()
mux.Handle("/custom/", CustomHandler{})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
if req.URL.Path != "/" {
http.NotFound(w, req)
return
}
fmt.Fprintf(w, "Welcome to the home page!")
})

// 监听srv.Addr确定的TCP地址，并且会调用Serve方法处理接收到的连接
// 必须提供证书文件和对应的私钥文件
// 如果证书是由权威机构签发的，certFile参数必须是顺序串联的服务端证书和CA证书
// 如果srv.Addr为空字符串，会使用":https"
if err := http.ListenAndServeTLS(":8443", "cert.pem", "key.pem", mux); err != nil {
log.Fatal(err)
}
}

func exampleServer() {
// 初始化server，定义了运行HTTP服务端的参数。Server的零值是合法的配置
srv := &http.Server{

// 监听的TCP地址，如果为空字符串会使用":http"
Addr: ":8080",

// 调用的处理器，如为nil会调用http.DefaultServeMux
Handler: nil,

// 请求的读取操作在超时前的最大持续时间
ReadTimeout: 0,

// 回复的写入操作在超时前的最大持续时间
WriteTimeout: 0,

// 允许读取请求头的时间。连接的读取截止时间在读取头之后重置，处理程序可以决定什么对主体来说太慢
ReadHeaderTimeout: 0,

// 启用keep alives时等待下一个请求的最大时间
// 如果idleTimeout为0，则使用readTimeout的值。如果两者都为零，则使用readHeaderTimeout
IdleTimeout: 0,

// 请求的头域最大长度，如为0则用DefaultMaxHeaderBytes
MaxHeaderBytes: 0,

// 可选的TLS配置，用于ListenAndServeTLS方法
TLSConfig: &tls.Config{},

// 指定一个可选的回调函数，该函数会在一个与客户端的连接改变状态时被调用
ConnState: func(conn net.Conn, state http.ConnState) {
if err := conn.Close(); err != nil {
log.Fatal(err)
}
},

// ErrorLog指定一个可选的日志记录器，用于记录接收连接时的错误和处理器不正常的行为
// 如果本字段为nil，日志会通过log包的标准日志记录器写入os.Stderr
ErrorLog: nil,
}

// 控制是否允许HTTP闲置连接重用（keep-alive）功能，默认该功能总是被启用的
// 只有资源非常紧张的环境或者服务端在关闭进程中时，才应该关闭该功能
srv.SetKeepAlivesEnabled(true)

// 创建TCP服务监听
l, err := net.Listen("tcp", "127.0.0.1:8081")
if err != nil {
log.Fatal(err)
}

// 接手监听器l收到的每一个连接，并为每一个连接创建一个新的服务go程
// 该go程会读取请求，然后调用srv.Handler回复请求
if err := srv.Serve(l); err != nil {
log.Fatal(err)
}

// 接手l上的传入连接，为每个连接创建一个新的服务例程。服务程序读取请求，然后调用srv.Handler来回复它们
// 此外，如果服务器的TLSConfig.Certificates和TLSConfig.GetCertificate都未被填充，则必须提供包含服务器的证书和匹配私钥的文件
// 如果证书由证书颁发机构签署，则certFile应该是服务器的串联证书，任何中间件和CA的证书
// 对于HTTP/2支持，在调用Serve之前，应将srv.TLSConfig初始化为提供的侦听器的TLS配置
// 如果srv.TLSConfig非零，并且在Config.NextProtos中不包含字符串“h2”，则不启用HTTP/2支持
if err := srv.ServeTLS(l, "cert.pem", "key.pem"); err != nil {
log.Fatal(err)
}

// 监听srv.Addr指定的TCP地址，并且会调用Serve方法接收到的连接
// 如果srv.Addr为空字符串，会使用":http"
// 效果等同于http.ListenAndServe()
if err := srv.ListenAndServe(); err != nil {
log.Fatal(err)
}

// 监听srv.Addr确定的TCP地址，并且会调用Serve方法处理接收到的连接
// 必须提供证书文件和对应的私钥文件
// 如果证书是由权威机构签发的，certFile参数必须是顺序串联的服务端证书和CA证书
// 如果srv.Addr为空字符串，会使用":https"
// 效果等同于http.ListenAndServeTLS
if err := srv.ListenAndServeTLS("cert.pem", "key.pem"); err != nil {
log.Fatal(err)
}

// 正常关闭服务器而不中断任何活动连接
// 首先关闭所有打开的监听程序，然后关闭所有空闲连接，然后无限期地等待连接返回到空闲状态然后关闭
// 如果提供的Context在关闭完成之前到期，Shutdown将返回Context的错误，否则返回关闭服务器的底层侦听器返回的任何错误
// 当调用Shutdown时，Serve，ListenAndServe和ListenAndServeTLS立即返回ErrServerClosed。确保程序不会退出，而是等待Shutdown返回
// 不会尝试关闭或等待被劫持的连接，如WebSockets。如果需要，Shutdown的调用者应该分别通知关闭的这种长期连接并等待
if err := srv.Shutdown(context.Background()); err != nil {
log.Fatal(err)
}

// 注册一个函数来调用Shutdown
// 这可以用于正常关闭经过NPN/ALPN协议升级或已被劫持的连接
// 此功能应启动特定于协议的正常关机，但不应等待关机完成
srv.RegisterOnShutdown(func() {
if err := srv.Shutdown(context.Background()); err != nil {
log.Fatal(err)
}
})

// 立即关闭所有活动的net.listener和state statenew、state active或stateidle中的任何连接
// 要正常关机，请使用Shutdown
// 不试图关闭（甚至不知道）任何被劫持的连接，如websockets。
// 返回关闭服务器的基础侦听器返回的任何错误
if err := srv.Close(); err != nil {
log.Fatal(err)
}
}

func exampleServerHtml() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/html; charset=utf-8")
w.Write([]byte("<p>Hello World!</p>"))
})
log.Fatal(http.ListenAndServe(":8080", nil))
}

func exampleTransport() {
uri, _ := url.Parse("http://www.baidu.com")

// 实现了RoundTripper接口，支持http、https和http/https代理。Transport类型可以缓存连接以在未来重用
// RoundTripper接口是具有执行单次HTTP事务的能力（接收指定请求的回复）的接口。
// RoundTripper接口的类型必须可以安全的被多线程同时使用
transport := &http.Transport{

// 指定一个对给定请求返回代理的函数
// 如果该函数返回了非nil的错误值，请求的执行就会中断并返回该错误。
// 如果Proxy为nil或返回nil的*URL置，将不使用代理
Proxy: http.ProxyURL(uri),

// 指定一个Dial函数，用于创建未加密TCP连接
// 如果DialContext为nil（下面不推荐使用的Dial也为nil），则使用net.Dial
DialContext: nil,

// 指定一个可选的Dial函数，用于为非代理的https请求创建TLS连接
DialTLS: nil,

// 指定用于tls.Client的TLS配置信息
// 如果该字段为nil，会使用默认的配置信息
TLSClientConfig: nil,

// 指定等待TLS握手完成的最长时间。零值表示不设置超时
TLSHandshakeTimeout: 0,

// 如果DisableKeepAlives为true，会禁止不同HTTP请求之间TCP连接的重用
DisableKeepAlives: false,

// 如果DisableCompression为true，会禁止Transport在请求中没有Accept-Encoding头时，主动添加"Accept-Encoding: gzip"头，以获取压缩数据
// 如果Transport自己请求gzip并得到了压缩后的回复，它会主动解压缩回复的主体
// 但如果用户显式的请求gzip压缩数据，Transport是不会主动解压缩的
DisableCompression: false,

// 控制所有主机的最大空闲（保持活动）连接数。零表示无限制
MaxIdleConns: 0,

// 如果MaxIdleConnsPerHost!=0，会控制每个主机下的最大闲置连接
// 如果MaxIdleConnsPerHost==0，会使用DefaultMaxIdleConnsPerHost
MaxIdleConnsPerHost: 0,

// 可以选择限制每个主机的连接总数，包括拨号、活动和空闲状态的连接
// 如果违反限制，拨号将被阻止。零值无限制
MaxConnsPerHost: 0,

// 空闲（保持活动）连接在关闭之前保持空闲状态的最长时间。零值无限制
IdleConnTimeout: 0,

// 指定在发送完请求（包括其可能的主体）之后，等待接收服务端的回复的头域的最大时间
// 零值表示不设置超时。该时间不包括获取回复主体的时间
ResponseHeaderTimeout: 0,

// 指定在连接请求期间发送到代理的头(可选)
ProxyConnectHeader: nil,

// 指定对服务器响应头中允许的响应字节数的限制。零值无限制
MaxResponseHeaderBytes: 0,
}

// 注册一个新的名为scheme的协议。transport会将使用scheme协议的请求转交给rt。rt有责任模拟HTTP请求的语义。
// RegisterProtocol可以被其他包用于提供"ftp"或"file"等协议的实现
transport.RegisterProtocol("test", http.NewFileTransport(http.Dir("/tmp/")))

// 关闭所有之前的请求建立但目前处于闲置状态的连接。本方法不会中断正在使用的连接
transport.CloseIdleConnections()

// 创建一个*http.Request
req, err := http.NewRequest("GET", "http://www.google.com/robots.txt", nil)
if err != nil {
log.Fatal(err)
}

// 高层次的HTTP客户端支持（如管理cookie和重定向）请参见Get、Post等函数和Client类型
transport.RoundTrip(req)
}
######################################################################################
D:\go\go\go标准库示例\net\net-mail.go

package main
import (
"fmt"
"io/ioutil"
"log"
"net/mail"
"strings"
)

// mail包实现了邮件的解析
func main() {
// 解析邮箱地址
exampleParseAddress()

// 读取邮件内容
exampleReadMessage()
}

func exampleParseAddress() {
var list = "Alice <alice@example.com>, Bob <bob@example.com>, Eve <eve@example.com>"

// 解析一串邮箱地址
emails, err := mail.ParseAddressList(list)
if err != nil {
log.Fatal(err)
}
for _, v := range emails {
fmt.Println(v.Name, v.Address)
}

// 解析单个邮箱地址
address, err := mail.ParseAddress("Alice <alice@example.com>")
if err != nil {
log.Fatal(err)
}
fmt.Println(address.Name, address.Address)
}

func exampleReadMessage() {
msg := `Date: Mon, 23 Jun 2015 11:40:36 -0400
From: Gopher <from@example.com>
To: Another Gopher <to@example.com>
Subject: Gophers at Gophercon
Message body
`

// 解析邮件信息
// 从reader读取一个邮件信息，会解析邮件头域，消息主体可以从r/msg.Body中读取
m, err := mail.ReadMessage(strings.NewReader(msg))
if err != nil {
log.Fatal(err)
}

// 邮件头域
header := m.Header

// 回键key对应的第一个值，如果没有对应值，将返回空字符串
fmt.Println("Date:", header.Get("Date"))
fmt.Println("From:", header.Get("From"))
fmt.Println("To:", header.Get("To"))
fmt.Println("Subject:", header.Get("Subject"))

// 将键key对应的值（字符串）作为邮箱地址列表解析并返回
fmt.Println(header.AddressList("From"))

// 读取body内容
body, err := ioutil.ReadAll(m.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", body)
}
######################################################################################
D:\go\go\go标准库示例\net\net-rpc.go

package main
import (
"fmt"
"log"
"net"
"net/http"
"net/rpc"
"strings"
)

// rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问
// 服务端注册一个对象，使它作为一个服务被暴露，服务的名字是该对象的类型名
// 注册之后，对象的导出方法就可以被远程访问
// 服务端可以注册多个不同类型的对象（服务），但注册具有相同类型的多个对象是错误的
func main() {
// rpc服务端到客户端的完整示例

example()

example2()
}

type Hello struct {}

func (h *Hello) Say(args *[]string, reply *string) error {
*reply = strings.Join(*args, " ")
return nil
}

func example() {
// 初始化Hello
hello := new(Hello)

// 初始化服务端
// 创建并返回一个*rpc.Server
server := rpc.NewServer()

// 在server注册并公布rcvr的方法集
// 满足: 方法是导出的；方法有两个参数，都是导出类型或内建类型；方法的第二个参数是指针；方法只有一个error接口类型的返回值
server.Register(hello)

// 类似Register，但使用提供的name代替rcvr的具体类型名作为服务名
server.RegisterName("Hello", hello)

// 监听端口
l, err := net.Listen("tcp", "127.0.0.1:1234")
if err != nil {
log.Fatalf("net.Listen tcp :0: %v", err)
}

// 接收监听器l获取的连接，然后服务每一个连接。Accept会阻塞，调用者应另开线程："go server.Accept(l)"
go server.Accept(l)

// 注册server的RPC信息HTTP处理器对应到rpcPath，注册server的debug信息HTTP处理器对应到debugPath
// HandleHTTP会注册到http.DefaultServeMux。之后，仍需要调用http.Serve()，一般会另开线程："go http.Serve(l, nil)"
server.HandleHTTP("/hello", "/debug")

// 将addr作为TCP地址解析并返回
address, err := net.ResolveTCPAddr("tcp", "127.0.0.1:1234")
if err != nil {
log.Fatal("ResolveTCPAddr error: ", err)
}

// 在网络协议net上连接本地地址laddr和远端地址raddr
// net必须是"tcp"、"tcp4"、"tcp6"；如果laddr不是nil，将使用它作为本地地址，否则自动选择一个本地地址
conn, _ := net.DialTCP("tcp", nil, address)
defer conn.Close()

// 初始化客户端
// 返回一个新的rpc.Client，以管理对连接另一端的服务的请求。它添加缓冲到连接的写入侧，以便将回复的头域和有效负载作为一个单元发送
client := rpc.NewClient(conn)
defer client.Close()

// 设置参数
args := &[]string{"Hello", "World!"}

// 初始化接收
reply := new(string)
err = client.Call("Hello.Say", args, reply)
if err != nil {
log.Fatal("Hello error:", err)
}
log.Println(*reply)
}

func example2() {
hello := new(Hello)
rpc.Register(hello)
rpc.HandleHTTP()

// 设置服务端监听
l, e := net.Listen("tcp", ":1234")
if e != nil {
log.Fatal("listen error:", e)
}
go http.Serve(l, nil)

// 客户端连接服务端
client, err := rpc.DialHTTP("tcp", "127.0.0.1:1234")
if err != nil {
log.Fatal("dialing:", err)
}

args := &[]string{"Hello", "Gopher!"}
reply := new(string)
err = client.Call("Hello.Say", args, reply)
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Println(*reply)
}
######################################################################################
D:\go\go\go标准库示例\net\net-smtp.go

package main
import (
"crypto/tls"
"fmt"
"log"
"net"
"net/smtp"
)

// smtp包实现了简单邮件传输协议（SMTP）
// 本包实现了以下扩展：8BITMIME、AUTH、STARTTLS
func main() {
// 邮件客户端发送邮件示例
exampleDial()

// 使用网络链接发送邮件示例
exampleClient()

// 简单的发送邮件示例
exampleSendMail()
}

func exampleDial() {
// 返回一个连接到地址为addr的SMTP服务器的*smtp.Client；addr必须包含端口号
c, err := smtp.Dial("mail.example.com:25")
if err != nil {
log.Fatal(err)
}

// 发送给服务端一个HELO或EHLO命令
// 本方法只有使用者需要控制使用的本地主机名时才应使用，否则程序会将本地主机名设为“localhost”，Hello方法只能在最开始调用
if err := c.Hello("localhost"); err != nil {
log.Fatal(err)
}

// 返回服务端是否支持某个扩展，扩展名是大小写不敏感的
// 如果扩展被支持，方法还会返回一个包含指定给该扩展的各个参数的字符串
fmt.Println(c.Extension("8BITMIME"))

// 返回一个实现了PLAIN身份认证机制的Auth接口
// 返回的接口使用给出的用户名和密码，通过TLS连接到主机认证，采用identity为身份管理和行动（通常应设identity为""，以便使用username为身份）
auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")

// 返回一个实现了CRAM-MD5身份认证机制的Auth接口
// 返回的接口使用给出的用户名和密码，采用响应——回答机制与服务端进行身份认证
smtp.CRAMMD5Auth("user@example.com", "password")

// 使用提供的认证机制进行认证。失败的认证会关闭该连接。只有服务端支持AUTH时，本方法才有效。（但是不支持时，调用会成功）
if err := c.Auth(auth); err != nil {
log.Fatal(err)
}

// 发送STARTTLS命令，并将之后的所有数据往来加密
// 只有服务器附加了STARTTLS扩展，这个方法才有效
c.StartTLS(&tls.Config{})

// 检查一个邮箱地址在其服务器是否合法，如果合法会返回nil
// 但非nil的返回值并不代表不合法，因为许多服务器出于安全原因不支持这种查询
c.Verify("user@example.com")

// 发送发件人邮箱地址
// 发送MAIL命令和邮箱地址from到服务器
// 如果服务端支持8BITMIME扩展，本方法会添加BODY=8BITMIME参数
// 方法初始化一次邮件传输，后应跟1到多个Rcpt方法的调用
if err := c.Mail("sender@example.org"); err != nil {
log.Fatal(err)
}

// 发送收件人邮箱地址
// 发送RCPT命令和邮箱地址to到服务器
// 调用Rcpt方法之前必须调用了Mail方法，之后可以再一次调用Rcpt方法，也可以调用Data方法
if err := c.Rcpt("recipient@example.net"); err != nil {
log.Fatal(err)
}

// 发送DATA指令到服务器并返回一个io.WriteCloser，用于写入邮件信息
// 调用者必须在调用c的下一个方法之前关闭这个io.WriteCloser。方法必须在一次或多次Rcpt方法之后调用
wc, err := c.Data()
if err != nil {
log.Fatal(err)
}

// 关闭
defer wc.Close()

// 写入邮件内容
if _, err := wc.Write([]byte("Hello World!")); err != nil {
log.Fatal(err)
}

// 发送QUIT命令并关闭到服务端的连接
if err := c.Quit(); err != nil {
log.Fatal(err)
}

// 关闭连接
//c.Close()

// 向服务端发送REST命令，中断当前的邮件传输
//c.Reset()
}

func exampleClient() {
addr := "mail.example.com:25"
conn, err := net.Dial("tcp", addr)
if err != nil {
log.Fatal("Dialing Error:", err)
}

//分解主机端口字符串
host, _, err := net.SplitHostPort(addr)
if err != nil {
log.Fatal(err)
}

// 使用已经存在的连接conn和作为服务器名的host（用于身份认证）来创建一个*smtp.Client
smtp.NewClient(conn, host)
}

func exampleSendMail() {
// 邮件服务器地址
addr := "mail.example.com:25"

// 返回一个实现了PLAIN身份认证机制的Auth接口
// 返回的接口使用给出的用户名和密码，通过TLS连接到主机认证，采用identity为身份管理和行动（通常应设identity为""，以便使用username为身份）
auth := smtp.PlainAuth("", "user@example.com", "password", "mail.example.com")

// 发件人
from := "sender@example.org"

// 收件人集合
to := []string{"recipient@example.net"}

// 邮件内容
msg := []byte("To: recipient@example.net\r\n" +
"Subject: discount Gophers!\r\n" +
"\r\n" +
"This is the email body.\r\n")

// 发送邮件，封装了smtp.Client
// 连接到addr指定的服务器；如果支持会开启TLS；如果支持会使用a认证身份；然后以from为邮件源地址发送邮件msg到目标地址to（可以是多个目标地址：群发）
if err := smtp.SendMail(addr, auth, from, to, msg); err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\net\net-textproto.go

package main
import (
"bufio"
"bytes"
"fmt"
"io/ioutil"
"log"
"net/textproto"
)

// textproto实现了对基于文本的请求/回复协议的一般性支持，包括HTTP、NNTP和SMTP
func main() {

// 基础读写
example()
}

func example() {
// 声明buffer
var buf bytes.Buffer

// 根据bufio.Writer创建writer
w := textproto.NewWriter(bufio.NewWriter(&buf))

// 写入格式化的输出，结尾自动添加\r\n
if err := w.PrintfLine("Hello %s!", "World"); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())

// 返回一个写入器，可以用来为 w 写一个点编码
// 它需要在需要时插入前导点，将行结束符\n 转换为\r\n，并在 DotWriter 关闭时添加最后的\r\n 行
// 调用者应在下一次调用 w 上的方法之前关闭 DotWriter
d := w.DotWriter()

// 写入
if _, err := d.Write([]byte("abc\n.def\n..ghi\n.jkl\n.")); err != nil {
log.Fatal(err)
}

// 关闭dotWriter，应在下一次调用 w 上的方法之前关闭
if err := d.Close(); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())

// 根据bufio.Reader创建一个reader
r := textproto.NewReader(bufio.NewReader(&buf))

// 从 r 读取一行，从返回的字符串中删除最后的\n或\r\n
fmt.Println(r.ReadLine())

// 返回一个新的 Reader，它使用从 r 读取的点编码块的解码文本满足 Reads
// 返回的 Reader 只有在下一次调用 r 时才有效
// 点编码是用于文本协议（如 SMTP）中的数据块的常用成帧
// 数据由一系列行组成，每行以“\ r \ n”结尾
// 序列本身结束于只包含一个点的一行：“。\ r \ n”。以点开头的行会用另外一个点进行转义，以避免看起来像序列的结尾
dr := r.DotReader()

// 读取内容
b ,err := ioutil.ReadAll(dr)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(b))
}
######################################################################################
D:\go\go\go标准库示例\net\net-url.go

package main
import (
"fmt"
"log"
"net/url"
)

// url包解析URL并实现了查询的逸码
func main() {
// url编码/解码
example()

// 创建/解析url
exampleURL()

// 创建/解析url参数
exampleQuery()

// 创建url用户名和密码信息
exampleUser()
}

func example() {
s := "https://www.baidu.com?test=1&name=测试"

// url编码
se := url.QueryEscape(s)
fmt.Println("urlEncode:", se)

// url解码
sd, err := url.QueryUnescape(se)
if err != nil {
log.Fatal(err)
}
fmt.Println("urlDecode:", sd)
}



func exampleURL() {
// 创建URL，结构体各参数意义参见 解析URL部分
//ul := url.URL{}
// 解析URL，本函数会假设rawurl是在一个HTTP请求里，因此会假设该参数是一个绝对URL或者绝对路径，并会假设该URL没有#fragment后缀。（网页浏览器会在去掉该后缀后才将网址发送到网页服务器）
//url.ParseRequestURI("http://bing.com/search?q=dotnet")
// 解析URL，rawurl可以是绝对地址，也可以是相对地址
u, err := url.Parse("http://bing.com/search?q=dotnet")
if err != nil {
log.Fatal(err)
}

// 协议名称http或https
fmt.Println("Scheme:", u.Scheme)

// 域名加端口
fmt.Println("Host:", u.Host)

// 编码后的不透明数据
fmt.Println("Opaque", u.Opaque)

// 用户名和密码信息
fmt.Println("User:", u.User)

// path路径
fmt.Println("Path:", u.Path)

// 编码后的查询字符串，没有'?'
fmt.Println("RawQuery:", u.RawQuery)

// 引用的片段（文档位置），没有'#'
fmt.Println("Fragment:", u.Fragment)
u.Scheme = "https"
u.Host = "google.com"

// 判断url是否绝对地址
fmt.Println("IsAbs:", u.IsAbs())

// 域名
fmt.Println("Hostname:", u.Hostname())

// 端口
fmt.Println("Port:", u.Port())

// 转字符串显示url
fmt.Println("String:", u.String())

// 返回 u.Path 的转义形式
fmt.Println("EscapedPath:", u.EscapedPath())

// 返回在 u 的 HTTP 请求中使用的编码 path?query 或 opaque?query 字符串
fmt.Println("RequestURI:", u.RequestURI())
text, err := u.MarshalBinary()
if err != nil {
log.Fatal(err)
}
fmt.Printf("MarshalBinary: %s\n", string(text))
if err := u.UnmarshalBinary(text); err != nil {
log.Fatal(err)
}
fmt.Println("UnmarshalBinary: ok")

// 解析RawQuery字段并返回其表示的url.Values类型键值对
q := u.Query()

// 将key对应的值集设为value，它会替换掉已有的值集
q.Set("q", "golang")

// 将value添加到key关联的值集里原有的值的后面
q.Add("say", "hello")

// 获取key对应的值集的第一个值。如果没有对应key的值集会返回空字符串
fmt.Println(q.Get("say"))

// 将v编码为url编码格式("bar=baz&foo=quux")，编码时会以键进行排序
fmt.Println(q.Encode())

// 删除key关联的值集
q.Del("say")

fmt.Println(u)

// 解析一个相对路径的url
uri, err := url.Parse("../../..//search?q=test")
if err != nil {
log.Fatal(err)
}

// 根据一个绝对URI将一个URI补全为一个绝对URI
// 参数ref可以是绝对URI或者相对URI，返回一个新的URL实例，即使该实例和u或者ref完全一样
// 如果ref是绝对URI，本方法会忽略参照URI并返回ref的一个拷贝
uriNew := u.ResolveReference(uri)
fmt.Println(uriNew.String())
}

func exampleQuery() {
// 解析url参数
// 解析一个URL编码的查询字符串，并返回可以表示该查询的Values类型的字典
// 本函数总是返回一个包含了所有合法查询参数的非nil字典，err用来描述解码时遇到的（如果有）第一个错误
m, err := url.ParseQuery(`x=1&y=2&y=3;z`)
if err != nil {
log.Fatal(err)
}
fmt.Println(m)

// 创建url参数, 可以直接用url.Value结构
params := url.Values{}

// 设置参数对
params.Set("say", "hello")
params.Set("test", "123")
params.Set("q", "Go")
fmt.Println(params.Encode())
}

func exampleUser() {
// 返回一个用户名设置为username的不设置密码的*url.Userinfo
u := url.User("gopher")

// 返回string格式
fmt.Println(u.String())

// 返回用户名
fmt.Println(u.Username())

// 如果设置了密码，返回密码和true，否则会返回false
fmt.Println(u.Password())

// 返回一个用户名设置为username、密码设置为password的*url.Userinfo
up := url.UserPassword("gopher", "123123")
fmt.Println(up.String())
fmt.Println(up.Password())
}
######################################################################################
D:\go\go\go标准库示例\net\net.go

package main
import (
"io"
"log"
"net"
"os"
)

// net包提供了可移植的网络I/O接口，包括TCP/IP、UDP、域名解析和Unix域socket
// 虽然本包提供了对网络原语的访问，大部分使用者只需要Dial、Listen和Accept函数提供的基本接口；以及相关的Conn和Listener接口
// crypto/tls包提供了相同的接口和类似的Dial和Listen函数
func main() {
// 创建服务
exampleServer()

// 客户端请求
exampleClient()
}

func exampleServer() {
// 创建tcp监听
// network必须是"tcp", "tcp4", "tcp6", "unix", "unixpacket".
l, err := net.Listen("tcp", ":8080")
if err != nil {
log.Fatal(err)
}
defer l.Close()
for {
// 等待连接
conn, err := l.Accept()
if err != nil {
log.Fatal(err)
}

go func(c net.Conn) {
// 拷贝接收内容并输出
io.Copy(os.Stdout, c)

// 关闭链接
c.Close()
}(conn)
}
}

func exampleClient() {
// 创建tcp连接
conn, err := net.Dial("tcp", ":8080")
if err != nil {
log.Fatal(err)
}

// 写入内容
if _, err := conn.Write([]byte("Hello World!")); err != nil {
log.Fatal(err)
}

// 关闭连接
if err := conn.Close(); err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\os\os-exec.go

package main

import (
"bytes"
"fmt"
"log"
"os/exec"
"strings"
)

// exec包执行外部命令
// 它包装了os.StartProcess函数以便更容易的修正输入和输出，使用管道连接I/O，以及作其它的一些调整
func main() {
// 执行命令
exampleCommand()

// 查询环境变量
exampleLookPath()
}

func exampleLookPath() {
// 在环境变量PATH指定的目录中搜索可执行文件，如file中有斜杠，则只在当前目录搜索
// 返回完整路径或者相对于当前目录的一个相对路径
path, err := exec.LookPath("fortune")
if err != nil {
fmt.Println("error: ", err)
} else {
fmt.Printf("fortune is available at %s\n", path)
}
}

func exampleCommand() {
cmd := exec.Command("go", "doc", "exec")
// 设置输入内容
cmd.Stdin = strings.NewReader("")

// 声明buffer
var out bytes.Buffer

// 设置输出内容填充地址
cmd.Stdout = &out

// 执行c包含的命令，并阻塞直到完成
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
fmt.Println(out.String())
}
######################################################################################
D:\go\go\go标准库示例\os\os-signal.go


package main

import (
"fmt"
"os"
"os/signal"
"syscall"
)

// signal包实现了对输入信号的访问
func main() {
// 初始化一个信号channel
c := make(chan os.Signal, 1)

// 让signal包将输入信号转发到c。如果没有列出要传递的信号，会将所有输入信号传递到c；否则只传递列出的输入信号
// signal包不会为了向c发送信息而阻塞（就是说如果发送时c阻塞了，signal包会直接放弃）
// 调用者应该保证c有足够的缓存空间可以跟上期望的信号频率。对使用单一信号用于通知的通道，缓存为1就足够了
signal.Notify(c, syscall.SIGINT, syscall.SIGKILL)
s := <-c
fmt.Println("Got signal:", s)

// 让signal包停止向c转发信号
// 它会取消之前使用c调用的所有Notify的效果。当Stop返回后，会保证c不再接收到任何信号
signal.Stop(c)
}
######################################################################################
D:\go\go\go标准库示例\os\os-user.go


package main

import (
"fmt"
"log"
"os/user"
)

// user包允许通过名称或ID查询用户帐户
func main() {
// 根据用户名查询用户
exampleLookup()

// 获取用户账号
exampleCurrent()
}

func exampleLookup() {
// 根据用户名查询用户
u, err := user.Lookup("root")
if err != nil {
log.Fatal(err)
}
fmt.Println("Lookup Name:", u.Name)

// 根据用户ID查询用户
ui, err :=  user.LookupId("501")
if err != nil {
log.Fatal(err)
}
fmt.Println("Lookup Uid:", ui.Uid)

// 根据组ID查询组
gi, err := user.LookupGroupId("20")
if err != nil {
log.Fatal(err)
}
fmt.Println( "Lookup Gid:", gi.Gid)

// 根据组名称查询组
g, err := user.LookupGroup("staff")
if err != nil {
log.Fatal(err)
}
fmt.Println("Lookup GroupName:", g.Name)
}

func exampleCurrent() {
// 返回当前的用户帐户
u, err := user.Current()
if err != nil {
log.Fatal(err)
}

// 用户名
fmt.Println("Name:", u.Name)

// 登陆名
fmt.Println("Username:", u.Username)

// 用户文件夹路径
fmt.Println("HomeDir:", u.HomeDir)

// 用户ID
fmt.Println("Uid:", u.Uid)

// 用户组ID
fmt.Println("Gid:", u.Gid)

// 用户所属组ID列表
fmt.Println(u.GroupIds())
}
######################################################################################
D:\go\go\go标准库示例\os\os.go

package main
import (
"fmt"
"log"
"os"
"time"
)

// os包提供了操作系统函数的不依赖平台的接口
// 设计为Unix风格的，虽然错误处理是go风格的；失败的调用会返回错误值而非错误码
// 通常错误值里包含更多信息。例如，如果某个使用一个文件名的调用（如Open、Stat）失败了，打印错误时会包含该文件名，错误类型将为*PathError，其内部可以解包获得更多信息
// os包的接口规定为在所有操作系统中都是一致的。非公用的属性可以从操作系统特定的syscall包获取
func main() {
// 获取系统基本信息
example()

// 创建文件夹
exampleDir()

// 文件操作
exampleFile()

// 文件改变
exampleChange()

// 文件操作模式
exampleFileMode()

// 环境变量
exampleEnv()

// 进程操作
exampleProcess()

// 获取命令行参数
exampleArgs()
}

const (
DirPath = "testdata/"
FilePath = "testdata/test_os.txt"
NewFilePath = "testdata/test_os_new.txt"
)

func example() {
// 返回内核提供的主机名
fmt.Println(os.Hostname())

// 返回底层的系统内存页的尺寸
fmt.Println("agesize:", os.Getpagesize())

// 返回调用者的用户ID
fmt.Println("uid:", os.Getuid())

// 返回调用者的有效用户ID
fmt.Println("euid:", os.Geteuid())

// 返回调用者的组ID
fmt.Println("gid:", os.Getgid())

// 返回调用者的有效组ID
fmt.Println("egid:",os.Getegid())

// 返回调用者所属的所有用户组的组ID
fmt.Println(os.Getgroups())

// 返回调用者所在进程的进程ID
fmt.Println("pid:", os.Getpid())

// 返回调用者所在进程的父进程的进程ID
fmt.Println("ppid:",os.Getppid())

// 返回表示环境变量的格式为"key=value"的字符串的切片拷贝
fmt.Println(os.Environ())

// 返回对应当前工作目录的根路径。如果当前目录可以经过多条路径抵达（因为硬链接），Getwd会返回其中一个
fmt.Println(os.Getwd())

// 返回用于保管临时文件的默认目录
fmt.Println(os.TempDir())

// 返回用于用户的缓存数据的默认根目录。用户应该在这个目录中创建自己的特定于应用程序的子目录，并使用它
fmt.Println(os.UserCacheDir())

// 用户文件夹路径
fmt.Println(os.UserHomeDir())
}

func exampleDir() {
// 使用指定的权限和名称创建一个目录。如果出错，会返回*PathError底层类型的错误
if err := os.Mkdir(DirPath, os.ModePerm); err != nil {
log.Fatal(err)
}

// 使用指定的权限和名称创建一个目录，包括任何必要的上级目录，并返回nil，否则返回错误
// 权限位perm会应用在每一个被本函数创建的目录上
// 如果path指定了一个已经存在的目录，MkdirAll不做任何操作并返回nil
if err := os.MkdirAll(DirPath, os.ModePerm); err != nil {
log.Fatal(err)
}
}

func exampleFile() {
// 以读取的方式打开文件，文件不存在会报错
//os.Open(FilePath)

// 以读写方式打开文件，并且清空原始内容，如果文件不存在以0666操作模式创建文件
//os.Create(FilePath)

// 改变文件的大小，它不会改变I/O的当前位置。 如果截断文件，多出的部分就会被丢弃。如果出错，错误底层类型是*PathError
//os.Truncate(FilePath, 1024)

// 删除指定的文件或目录。如果出错，会返回*PathError底层类型的错误
//os.Remove(FilePath)

// 删除path指定的文件，或目录及它包含的任何下级对象。它会尝试删除所有东西，除非遇到错误并返回。如果path指定的对象不存在，会返回nil而不返回错误
//os.RemoveAll(FilePath)

// 创建硬链接。如果出错，会返回* LinkError底层类型的错误
//os.Link(FilePath, NewFilePath)

// 创建软连接。如果出错，会返回* LinkError底层类型的错误
//os.Symlink(FilePath, NewFilePath)

// 获取指定的软链接文件指向的文件的路径。如果出错，会返回*PathError底层类型的错误
//os.Readlink(NewFilePath)

// 以读写方式打开文件，并且内容写入方式为添加，如果文件不存在以0755操作模式创建文件
f, err := os.OpenFile(FilePath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0755)
if err != nil {
log.Fatal(err)
}

// 关闭文件
defer f.Close()

// 写入内容（向文件内添加内容）
if _, err := f.Write([]byte("appended some data\n")); err != nil {
log.Fatal(err)
}
}

func exampleChange() {
// 判断文件是否存在
if _, err := os.Stat(FilePath); err != nil {
if os.IsNotExist(err) {
fmt.Println("file does not exist")
} else {
log.Fatal(err)
}
}

// 修改指定文件的mode操作模式
// 如果name指定的文件是一个符号链接，它会修改该链接的目的地文件的mode。如果出错，会返回*PathError底层类型的错误
if err := os.Chmod(FilePath, 0644); err != nil {
log.Fatal(err)
}

// 修改指定文件的用户id和组id
// 如果name指定的文件是一个符号链接，它会修改该链接的目的地文件的用户id和组id。如果出错，会返回*PathError底层类型的错误
if err := os.Chown(FilePath, 501, 20); err != nil {
log.Fatal(err)
}

// 修改指定文件的用户id和组id
// 如果name指定的文件是一个符号链接，它会修改该符号链接自身的用户id和组id。如果出错，会返回*PathError底层类型的错误
if err := os.Lchown(FilePath, 501, 20); err != nil {
log.Fatal(err)
}

mtime := time.Date(2019, time.February, 1, 3, 4, 5, 0, time.UTC)
atime := time.Date(2019, time.March, 2, 4, 5, 6, 0, time.UTC)

// 修改指定文件的访问时间和修改时间，类似Unix的utime()或utimes()函数
// 底层的文件系统可能会截断/舍入时间单位到更低的精确度。如果出错，会返回*PathError底层类型的错误
if err := os.Chtimes(FilePath, atime, mtime); err != nil {
log.Fatal(err)
}

// 将当前工作目录修改为dir指定的目录。如果出错，会返回*PathError底层类型的错误
//if err := os.Chdir("/"); err != nil {
//	log.Fatal(err)
//}
}

func exampleFileMode() {
// 返回一个描述指定文件的FileInfo
// 如果指定的文件对象是一个符号链接，返回的FileInfo描述该符号链接的信息，本函数不会试图跳转该链接。如果出错，返回的错误值为*PathError类型
fi, err := os.Lstat(FilePath)
if err != nil {
log.Fatal(err)
}
fmt.Printf("permissions: %#o\n", fi.Mode().Perm()) // 0400, 0777, etc.
switch mode := fi.Mode(); {
case mode.IsRegular():
fmt.Println("regular file")
case mode.IsDir():
fmt.Println("directory")
case mode&os.ModeSymlink != 0:
fmt.Println("symbolic link")
case mode&os.ModeNamedPipe != 0:
fmt.Println("named pipe")
}
}

func exampleEnv() {
// 设置名为key的环境变量（临时）。如果出错会返回该错误
if err := os.Setenv("NAME", "Gopher"); err != nil {
log.Fatal(err)
}

// 检索并返回名为key的环境变量的值。如果不存在该环境变量会返回空字符串
fmt.Println(os.Getenv("NAME"))

// 检索并返回名为key的环境变量的值 和 是否存在的bool值。如果不存在布尔值为false
fmt.Println(os.LookupEnv("NAME"))

// 删除所有环境变量
//os.Clearenv()

// 使用指定函数替换s中的${var}或$var。例如，os.ExpandEnv(s)等价于os.Expand(s, os.Getenv)
fmt.Println(os.Expand("Hello $NAME!", func(s string) string { return "Gopher" }))

// 替换s中的${var}或$var为名为var 的环境变量的值。引用未定义环境变量会被替换为空字符串
fmt.Println(os.ExpandEnv("Hello ${NAME}!"))

// 取消设置单个环境变量
if err := os.Unsetenv("NAME"); err != nil {
log.Fatal(err)
}
}

func exampleProcess() {
// 初始化一个 保管将被StartProcess函数用于一个新进程的属性
attr := &os.ProcAttr{
Files: []*os.File{os.Stdin, os.Stdout, os.Stderr}, //其他变量如果不清楚可以不设定
}

// 使用提供的属性、程序名、命令行参数开始一个新进程
// StartProcess函数是一个低水平的接口
// os/exec包提供了高水平的接口，应该尽量使用该包。如果出错，错误的底层类型会是*PathError
p, err := os.StartProcess("/usr/bin/vim", []string{"/usr/bin/vim", "temp.txt"}, attr)
if err != nil {
log.Fatal(err)
}

// 根据进程id查找一个运行中的进程
p, err = os.FindProcess(p.Pid)
if err != nil {
log.Fatal(err)
}

// 立刻退出进程
if err := p.Kill(); err != nil {
log.Fatal(err)
}
}

func exampleArgs() {
// 获取命令行参数
// 第一个参数是命令本身，所以从第二个开始截取
args := os.Args[1:]
fmt.Println(args)
}
######################################################################################
D:\go\go\go标准库示例\path\path-filepath.go

package main
// filepath包实现了兼容各操作系统的文件路径的实用操作函数

func main() {

//返回所给路径的绝对路径
path, _ := filepath.Abs("./1.txt");
fmt.Println(path);

//返回路径最后一个元素
fmt.Println(filepath.Base("./1.txt"));
//如果路径为空字符串，返回.
fmt.Println(filepath.Base(""));
//如果路径只有斜线，返回/
fmt.Println(filepath.Base("///"));

//返回等价的最短路径
//1.用一个斜线替换多个斜线
//2.清除当前路径.
//3.清除内部的..和他前面的元素
//4.以/..开头的，变成/
fmt.Println(filepath.Clean("C:/a/b/../c"));
fmt.Println(filepath.Clean("./1.txt"));

//返回路径最后一个元素的目录
//路径为空则返回.
fmt.Println(filepath.Dir("./a/b/c"));
fmt.Println(filepath.Dir("C:/a/b/c"));

//返回链接文件的实际路径
path2, _ := filepath.EvalSymlinks("1.lnk");
fmt.Println(path2);

//返回路径中的扩展名
//如果没有点，返回空
fmt.Println(filepath.Ext("./a/b/c/d.jpg"));

//将路径中的/替换为路径分隔符
fmt.Println(filepath.FromSlash("./a/b/c"));

//返回所有匹配的文件
match, _ := filepath.Glob("./*.go");
fmt.Println(match);

//判断路径是不是绝对路径
fmt.Println(filepath.IsAbs("./a/b/c"));
fmt.Println(filepath.IsAbs("C:/a/b/c"));

//连接路径，返回已经clean过的路径
fmt.Println(filepath.Join("C:/a", "/b", "/c"));

//匹配文件名，完全匹配则返回true
fmt.Println(filepath.Match("*", "a"));
fmt.Println(filepath.Match("*", "C:/a/b/c"));
fmt.Println(filepath.Match("\\b", "b"));

//返回以basepath为基准的相对路径
path3, _ := filepath.Rel("C:/a/b", "C:/a/b/c/d/../e");
fmt.Println(path3);

//将路径使用路径列表分隔符分开，见os.PathListSeparator
//linux下默认为:，windows下为;
fmt.Println(filepath.SplitList("C:/windows;C:/windows/system"));

//分割路径中的目录与文件
dir, file := filepath.Split("C:/a/b/c/d.jpg");
fmt.Println(dir, file);

//将路径分隔符使用/替换
fmt.Println(filepath.ToSlash("C:/a/b"));

//返回分区名
fmt.Println(filepath.VolumeName("C:/a/b/c"));

//遍历指定目录下所有文件
filepath.Walk("./", func(path string, info os.FileInfo, err error) error {
fmt.Println(path);
return nil;
});
// 操作方法如path包
}
######################################################################################
D:\go\go\go标准库示例\path\path.go

package main
import (
"fmt"
"path"
)

// path实现了对斜杠分隔的路径的实用操作函数

func main() {
var pathStr = "/testdata/test/"

// 返回路径的最后一个元素，在提取元素前会删掉末尾的斜杠
// 如果路径是""，会返回"."；如果路径是只有一个斜杆构成，会返回"/"
path.Base(pathStr) // test

// 通过单纯的词法操作返回和path代表同一地址的最短路径
// 它会不断的依次应用如下的规则，直到不能再进行任何处理：
// 1. 将连续的多个斜杠替换为单个斜杠
// 2. 剔除每一个.路径名元素（代表当前目录）
// 3. 剔除每一个路径内的..路径名元素（代表父目录）和它前面的非..路径名元素
// 4. 剔除开始一个根路径的..路径名元素，即将路径开始处的"/.."替换为"/"
path.Clean("a//c") // a/c

// 返回路径除去最后一个路径元素的部分，即该路径最后一个元素所在的目录
// 在使用Split去掉最后一个元素后，会简化路径并去掉末尾的斜杠
// 如果路径是空字符串，会返回"."；如果路径由1到多个斜杠后跟0到多个非斜杠字符组成，会返回"/"；其他任何情况下都不会返回以斜杠结尾的路径
path.Dir(pathStr) // /testdata/test

// 返回path文件扩展名
path.Ext("/a/test.html") // html

// 返回路径是否是一个绝对路径
path.IsAbs("/dev/null")

// 将路径从最后一个斜杠后面位置分隔为两个部分（dir和file）并返回
// 如果路径中没有斜杠，函数返回值dir会设为空字符串，file会设为path
// 两个返回值满足path == dir+file
dir, file := path.Split(pathStr)
fmt.Println(dir, file)

// 可以将任意数量的路径元素放入一个单一路径里，会根据需要添加斜杠
// 结果是经过简化的，所有的空字符串元素会被忽略
path.Join("a", "b/c") // /a/b/c

// 如果name匹配shell文件名模式匹配字符串，Match函数返回真
// Match要求匹配整个name字符串，而不是它的一部分。只有pattern语法错误时，会返回ErrBadPattern
/*
	匹配字符串语法：
		pattern:
			{ term }
		term:
			'*'                                  匹配0或多个非/的字符
			'?'                                  匹配1个非/的字符
			'[' [ '^' ] { character-range } ']'  字符组（必须非空）
			c                                    匹配字符c（c != '*', '?', '\\', '['）
			'\\' c                               匹配字符c
		character-range:
			c           匹配字符c（c != '\\', '-', ']'）
			'\\' c      匹配字符c
			lo '-' hi   匹配区间[lo, hi]内的字符
*/
path.Match("*", "abc")
}
######################################################################################
D:\go\go\go标准库示例\plugin\plugin.go

package main
import (
"log"
"plugin"
)

const PluginFile = "testdata/testPlugin.so"

// plugin包实现 Go 插件的加载和符号解析
// 注意plugin的源码需要在main包中，否则无法编译
func main() {
// 编译go plugin只需要在go build的时候带上--buildmode=plugin即可。命令如下：
// go build --buildmode=plugin -o pluginHello.so pluginHello.go
// 打开一个 Go 插件。如果路径已被打开，则返回现有的*plugin.Plugin。由多个 goroutines 并行使用是安全的
p ,err := plugin.Open(PluginFile)
if err != nil {
log.Fatal(err)
}

// 查找在插件 p 中搜索名为 symName 的符号
// 符号是任何导出的变量或函数，如果找不到该符号，它会报告错误。由多个 goroutines 并行使用是安全的
s, err := p.Lookup("test")
if err != nil {
log.Fatal(err)
}
if test, ok := s.(func()); ok {
test()
}
}
######################################################################################
D:\go\go\go标准库示例\reflect\reflect.go

package main
import (
"fmt"
"io"
"os"
"reflect"
)

// reflect包实现了运行时反射，允许程序操作任意类型的对象
// 典型用法是用静态类型interface{}保存一个值，通过调用TypeOf获取其动态类型信息，该函数返回一个Type类型值
// 调用ValueOf函数返回一个Value类型值，该值代表运行时的数据
// Zero接受一个Type类型参数并返回一个代表该类型零值的Value类型值
func main() {
example()

exampleType()

exampleValue()

exampleMake()
}

type Hello struct {
Name string   `json:"name"`
Age  int      `json:"age"`
Arr  []string `json:""`
}

func (h *Hello) Say() {
fmt.Println("Hello World!")
}

func (h Hello) Says() {
fmt.Println("Hello World!")
}

func exampleType() {
hello := Hello{}
// 返回接口中保存的值的类型，TypeOf(nil)会返回nil
t := reflect.TypeOf(hello)

// 返回该类型的元素类型，如果该类型的Kind不是Array、Chan、Map、Ptr或Slice，会panic
reflect.TypeOf(&hello).Elem()

// 返回该接口的具体类型
t.Kind()
fmt.Println("reflect.Struct:", t.Kind() == reflect.Struct)

// 返回该类型在自身包内的类型名，如果是未命名类型会返回""
fmt.Println("Name:", t.Name())

// 返回类型的包路径，即明确指定包的import路径，如"encoding/base64"
// 如果类型为内建类型(string, error)或未命名类型(*T, struct{}, []int)，会返回""
fmt.Println("PkgPath:", t.PkgPath())

// 返回类型的字符串表示。该字符串可能会使用短包名（如用base64代替"encoding/base64"）
// 也不保证每个类型的字符串表示不同。如果要比较两个类型是否相等，请直接用Type类型比较
fmt.Println("String:", t.String())

// 返回要保存一个该类型的值需要多少字节；类似unsafe.Sizeof
fmt.Println("Size:", t.Size())

// 返回当从内存中申请一个该类型值时，会对齐的字节数
fmt.Println("Align:", t.Align())

// 返回当该类型作为结构体的字段时，会对齐的字节数
fmt.Println("FieldAlign:", t.FieldAlign())

// 返回该类型的方法集中方法的数目
// 匿名字段的方法会被计算；主体类型的方法会屏蔽匿名字段的同名方法；
// 匿名字段导致的歧义方法会滤除
fmt.Println("NumMethod:", t.NumMethod())

// 返回该类型方法集中的第i个方法，i不在[0, NumMethod())范围内时，将导致panic
// 对非接口类型T或*T，返回值的Type字段和Func字段描述方法的未绑定函数状态
// 对接口类型，返回值的Type字段描述方法的签名，Func字段为nil
fmt.Println("Method:", t.Method(0))

// 根据方法名返回该类型方法集中的方法，使用一个布尔值说明是否发现该方法
// 对非接口类型T或*T，返回值的Type字段和Func字段描述方法的未绑定函数状态
// 对接口类型，返回值的Type字段描述方法的签名，Func字段为nil
fmt.Println(t.MethodByName("Says"))

// 返回struct类型的字段数（匿名字段算作一个字段），如非结构体类型将panic
fmt.Println("NumField:", t.NumField())

// 返回struct类型的第i个字段的类型，如非结构体或者i不在[0, NumField())内将会panic
fmt.Println("Field:", t.Field(0))

// 获取字段下的tag标签
// 使用Tag.Get时不存在的tag会返回空字符串
fmt.Println("Field Tag(json):", t.Field(0).Tag.Get("jsons"))

// 查找指定名称的tag，返回 tag内容 和 布尔值（用于判断是否存在tag）
// 当布尔值为false时，这个tag不存在
// 当布尔值为true时，tag内容为空字符串时，说明tag存在但是设为空值
fmt.Println(t.Field(2).Tag.Lookup("json"))

// 返回索引序列指定的嵌套字段的类型，
// 等价于用索引中每个值链式调用本方法，如非结构体将会panic
fmt.Println("FieldByIndex:", t.FieldByIndex([]int{1}))

// 返回该类型名为name的字段（会查找匿名字段及其子字段），
// 布尔值说明是否找到，如非结构体将panic
fmt.Println(t.FieldByName("Name"))

// 返回该类型第一个字段名满足函数match的字段，布尔值说明是否找到，如非结构体将会panic
fmt.Println(t.FieldByNameFunc(func(s string) bool { return s == "Name" }))

// 返回该类型的字位数。如果该类型的Kind不是Int、Uint、Float或Complex，会panic
//t.Bits()

// 返回array类型的长度，如非数组类型将panic
//t.Len()

// 返回map类型的键的类型。如非映射类型将panic
//t.Key()

// 返回一个channel类型的方向，如非通道类型将会panic
//t.ChanDir()

// 如果函数类型的最后一个输入参数是"..."形式的参数，IsVariadic返回true
// 如果这样，t.In(t.NumIn() - 1)返回参数的隐式的实际类型（声明类型的切片）
// 如非函数类型将panic
//t.IsVariadic()

// 返回func类型的参数个数，如果不是函数，将会panic
//t.NumIn()

// 返回func类型的第i个参数的类型，如非函数或者i不在[0, NumIn())内将会panic
//t.In(0)

// 返回func类型的返回值个数，如果不是函数，将会panic
//t.NumOut()

// 返回func类型的第i个返回值的类型，如非函数或者i不在[0, NumOut())内将会panic
//t.Out(0)

// 获取*io.Writer的Type
writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()

// 获取*os.File的Type
fileType := reflect.TypeOf((*os.File)(nil))

// 判断*os.File是否实现了*io.Writer接口
fmt.Println(fileType.Implements(writerType))

// 如果该类型的值可以直接赋值给u代表的类型，返回true
fmt.Println(fileType.AssignableTo(writerType))

// 如该类型的值可以转换为u代表的类型，返回true
fmt.Println(fileType.ConvertibleTo(writerType))
}

func exampleValue() {
hello := Hello{}

// 返回一个初始化为i接口保管的具体值的Value，ValueOf(nil)返回Value零值
v := reflect.ValueOf(hello)

// 返回v持有的接口保管的值的Value封装，或者v持有的指针指向的值的Value封装
// 如果v的Kind不是Interface或Ptr会panic；如果v持有的值为nil，会返回Value零值
reflect.ValueOf(&hello).Elem()

// 返回v持有的值的类型的Type表示
// 详细查看exampleType()
v.Type()

// 返回v持有的值的类型，如果v是Value零值，返回值为Invalid
v.Kind()
fmt.Println("reflect.String:", v.Kind() == reflect.String)

// 返回v是否持有一个值
// 如果v是Value零值会返回false，此时v除了IsValid、String、Kind之外的方法都会导致panic
// 绝大多数函数和方法都永远不返回Value零值。如果某个函数/方法返回了非法的Value，它的文档必须显式的说明具体情况
fmt.Println(v.IsValid())

// 判断v持有的值是否为nil
// v持有的值的分类必须是通道、函数、接口、映射、指针、切片之一；否则IsNil函数会导致panic
// 注意IsNil并不总是等价于go语言中值与nil的常规比较。例如：如果v是通过使用某个值为nil的接口调用ValueOf函数创建的，v.IsNil()返回true，但是如果v是Value零值，会panic
//v.IsNil()

// 返回v持有的布尔值，如果v的Kind不是Bool会panic
//v.Bool()

// 返回v持有的有符号整数（表示为int64），如果v的Kind不是Int、Int8、Int16、Int32、Int64会panic
//v.Int()

// 如果v持有值的类型不能无溢出的表示x，会返回true。如果v的Kind不是Int、Int8、Int16、Int32、Int64会panic
//v.OverflowInt(0)

// 返回v持有的无符号整数（表示为uint64），如v的Kind不是Uint、Uintptr、Uint8、Uint16、Uint32、Uint64会panic
//v.Uint()

// 如果v持有值的类型不能无溢出的表示x，会返回true。如果v的Kind不是Uint、Uintptr、Uint8、Uint16、Uint32、Uint64会panic
//v.OverflowUint(0)

// 返回v持有的浮点数（表示为float64），如果v的Kind不是Float32、Float64会panic
//v.Float()

// 如果v持有值的类型不能无溢出的表示x，会返回true。如果v的Kind不是Float32、Float64会panic
//v.OverflowFloat(0)

// 返回v持有的复数（表示为complex64），如果v的Kind不是Complex64、Complex128会panic
//v.Complex()

// 如果v持有值的类型不能无溢出的表示x，会返回true。如果v的Kind不是Complex64、Complex128会panic
//v.OverflowComplex(0)

// 将v持有的值作为一个指针返回
// 本方法返回值不是unsafe.Pointer类型，以避免程序员不显式导入unsafe包却得到unsafe.Pointer类型表示的指针
// 如果v的Kind不是Chan、Func、Map、Ptr、Slice或UnsafePointer会panic
// 如果v的Kind是Func，返回值是底层代码的指针，但并不足以用于区分不同的函数；只能保证当且仅当v持有函数类型零值nil时，返回值为0
// 如果v的Kind是Slice，返回值是指向切片第一个元素的指针。如果持有的切片为nil，返回值为0；如果持有的切片没有元素但不是nil，返回值不会是0
//v.Pointer()

// 返回v持有的[]byte类型值。如果v持有的值的类型不是[]byte会panic
//v.Bytes()

// 返回v持有的值的字符串表示
// 因为go的String方法的惯例，Value的String方法比较特别
// 和其他获取v持有值的方法不同：v的Kind是String时，返回该字符串；v的Kind不是String时也不会panic而是返回格式为"<T value>"的字符串，其中T是v持有值的类型
//v.String()

// 返回v持有的接口类型值的数据。如果v的Kind不是Interface会panic
//v.InterfaceData()

// 返回v[i:j]（v持有的切片的子切片的Value封装）；如果v的Kind不是Array、Slice或String会panic。如果v是一个不可寻址的数组，或者索引出界，也会panic
//v.Slice(0, 1)

// 是Slice的3参数版本，返回v[i:j:k] ；如果v的Kind不是Array、Slice或String会panic。如果v是一个不可寻址的数组，或者索引出界，也会panic
//v.Slice3(0, 1, 2)

// 返回v持有值的容量，如果v的Kind不是Array、Chan、Slice会panic
//v.Cap()

// 返回v持有值的长度，如果v的Kind不是Array、Chan、Slice、Map、String会panic
//v.Len()

// 返回v持有值的第i个元素。如果v的Kind不是Array、Chan、Slice、String，或者i出界，会panic
//v.Index(0)

// 返回v持有值里key持有值为键对应的值的Value封装，如果v的Kind不是Map，会panic
// 如果未找到对应值或者v持有值是nil映射，会返回Value零值
// key的持有值必须可以直接赋值给v持有值类型的键类型
//v.MapIndex(reflect.ValueOf("test"))

// 返回一个包含v持有值中所有键的Value封装的切片，该切片未排序。如果v的Kind不是Map会panic。如果v持有值是nil，返回空切片（非nil）
//v.MapKeys()

// 返回v持有的结构体类型值的字段数，如果v的Kind不是Struct会panic
//v.NumField()

// 返回结构体的第i个字段（的Value封装）。如果v的Kind不是Struct或i出界会panic
//v.Field(0)

// 返回索引序列指定的嵌套字段的Value表示，等价于用索引中的值链式调用本方法，如v的Kind非Struct将会panic
//v.FieldByIndex([]int{1})

// 返回该类型名为name的字段（的Value封装）（会查找匿名字段及其子字段），如果v的Kind不是Struct会panic；如果未找到会返回Value零值
//v.FieldByName("Name")

// 返回该类型第一个字段名满足match的字段（的Value封装）（会查找匿名字段及其子字段），如果v的Kind不是Struct会panic；如果未找到会返回Value零值
//v.FieldByNameFunc(func(s string) bool { return s == "Name" })

// 从v持有的通道接收并返回一个值（的Value封装）。如果v的Kind不是Chan会panic。方法会阻塞直到获取到值
// 如果返回值x对应于某个发送到v持有的通道的值，ok为true；如果因为通道关闭而返回，x为Value零值而ok为false
//v.Recv()

// 尝试从v持有的通道接收一个值，但不会阻塞。如果v的Kind不是Chan会panic
// 如果方法成功接收到一个值，会返回该值（的Value封装）和true；如果不能无阻塞的接收到值，返回Value零值和false；如果因为通道关闭而返回，返回值x是持有通道元素类型的零值的Value和false
//v.TryRecv()

// 向v持有的通道发送x持有的值。如果v的Kind不是Chan，或者x的持有值不能直接赋值给v持有通道的元素类型，会panic
//v.Send(reflect.ValueOf(5))

// 尝试向v持有的通道发送x持有的值，但不会阻塞。如果v的Kind不是Chan会panic
// 如果成功发送会返回true，否则返回false。x的持有值必须可以直接赋值给v持有通道的元素类型
//v.TrySend(reflect.ValueOf(5))

// 关闭v持有的通道，如果v的Kind不是Chan会panic
//v.Close()

// 使用输入的参数in调用v持有的函数
// 例如，如果len(in) == 3，v.Call(in)代表调用v(in[0], in[1], in[2])（其中Value值表示其持有值）
// 如果v的Kind不是Func会panic。它返回函数所有输出结果的Value封装的切片
// 和go代码一样，每一个输入实参的持有值都必须可以直接赋值给函数对应输入参数的类型
// 如果v持有值是可变参数函数，Call方法会自行创建一个代表可变参数的切片，将对应可变参数的值都拷贝到里面
//v.Call([]reflect.Value{reflect.ValueOf("Go"), reflect.ValueOf(10)})

// 调用v持有的可变参数函数，会将切片类型的in[len(in)-1]（的成员）分配给v的最后的可变参数
// 例如，如果len(in) == 3，v.Call(in)代表调用v(in[0], in[1], in[2])（其中Value值表示其持有值，可变参数函数的可变参数位置提供一个切片并跟三个点号代表"解切片"）
// 如果v的Kind不是Func或者v的持有值不是可变参数函数，会panic。它返回函数所有输出结果的Value封装的切片
// 和go代码一样，每一个输入实参的持有值都必须可以直接赋值给函数对应输入参数的类型
//v.CallSlice([]reflect.Value{reflect.ValueOf(9), reflect.ValueOf(10), reflect.ValueOf(11)})
// 返回v持有值的方法集的方法数目
fmt.Println(v.NumMethod())

// 返回v持有值类型的第i个方法的已绑定（到v的持有值的）状态的函数形式的Value封装
// 返回值调用Call方法时不应包含接收者；返回值持有的函数总是使用v的持有者作为接收者（即第一个参数）
// 如果i出界，或者v的持有值是接口类型的零值（nil），会panic
//v.Method(0)

// 返回v的名为name的方法的已绑定（到v的持有值的）状态的函数形式的Value封装
// 返回值调用Call方法时不应包含接收者；返回值持有的函数总是使用v的持有者作为接收者（即第一个参数）
// 如果未找到该方法，会返回一个Value零值
//v.MethodByName("Says")

// 判断是否是指针，返回是否可以获取v持有值的指针
// 可以获取指针的值被称为可寻址的。如果一个值是切片或可寻址数组的元素、可寻址结构体的字段、或从指针解引用得到的，该值即为可寻址的
fmt.Println(v.CanAddr())

// 返回一个持有指向v持有者的指针的Value封装
// 如果v.CanAddr()返回false，调用本方法会panic。Addr一般用于获取结构体字段的指针或者切片的元素（的Value封装）以便调用需要指针类型接收者的方法
//v.Addr()

// 返回指向v持有数据的地址的指针（表示为uintptr）以用作高级用途，如果v不可寻址会panic
//v.UnsafeAddr()

// 判断是否interface，如果返回true，v可以不导致panic的调用Interface方法
fmt.Println(v.CanInterface())

// 返回v当前持有的值（表示为/保管在interface{}类型），如果v是通过访问非导出结构体字段获取的，会导致panic
fmt.Println(v.Interface())

// 判断是否可以设置值
// 如果v持有的值可以被修改，会返回true。只有一个Value持有值可以被寻址同时又不是来自非导出字段时，它才可以被修改
// 如果返回false，调用Set或任何限定类型的设置函数（如SetBool、SetInt64）都会panic
fmt.Println(v.CanSet())

// 设置bool值。如果v的Kind不是Bool或者v.CanSet()返回false，会panic
//v.SetBool(true)

// 设置int值。如果v的Kind不是Int、Int8、Int16、Int32、Int64之一或者v.CanSet()返回false，会panic
//v.SetInt(0)

// 设置uint值。如果v的Kind不是Uint、Uintptr、Uint8、Uint16、Uint32、Uint64或者v.CanSet()返回false，会panic
//v.SetUint(0)

// 设置float值。如果v的Kind不是Float32、Float64或者v.CanSet()返回false，会panic
//v.SetFloat(0)

// 设置complex值。如果v的Kind不是Complex64、Complex128或者v.CanSet()返回false，会panic
//v.SetComplex(0)

// 设置[]byte值。如果v持有值不是[]byte类型或者v.CanSet()返回false，会panic
//v.SetBytes([]byte("Hello World!"))

// 设置string值。如果v的Kind不是String或者v.CanSet()返回false，会panic
//v.SetString("Hello World!")

// 设置指针值。如果v的Kind不是UnsafePointer或者v.CanSet()返回false，会panic
//v.SetPointer(&Hello{"Go", 12, []string{"Hello", "World"}})

// 设定值的容量。如果v的Kind不是Slice或者n出界（小于长度或超出容量），将导致panic
//v.SetCap(10)

// 设定值的长度。如果v的Kind不是Slice或者n出界（小于零或超出容量），将导致panic
//v.SetLen(10)

// 用来给v的映射类型持有值添加/修改键值对，如果val是Value零值，则是删除键值对。如果v的Kind不是Map，或者v的持有值是nil，将会panic
// key的持有值必须可以直接赋值给v持有值类型的键类型。val的持有值必须可以直接赋值给v持有值类型的值类型
//v.SetMapIndex(reflect.ValueOf("test"), reflect.ValueOf("Hello World!"))

// 将v的持有值修改为x的持有值。如果v.CanSet()返回false，会panic。x的持有值必须能直接赋给v持有值的类型
//v.Set(reflect.ValueOf("Hello"))
}

func exampleMake() {
var c chan int
var fn func(int) int
var m map[string]string
var sl = []int{1, 2, 3}

// 创建一个元素类型为typ、有buffer个缓存的channel类型的Value值
reflect.MakeChan(reflect.TypeOf(c), 1)

// 创建一个具有给定类型、包装函数fn的函数的Value封装。
// 当被调用时，该函数会将提供给它的参数转化为Value切片
// 执行results := fn(args)
// 将results中每一个result依次排列作为返回值
reflect.MakeFunc(reflect.TypeOf(fn), func(args []reflect.Value) (results []reflect.Value) { return []reflect.Value{args[0]} })

// 创建一个特定map类型的Value值
reflect.MakeMap(reflect.TypeOf(m))

// 创建一个具有n个初始空间的map类型的Value值
reflect.MakeMapWithSize(reflect.TypeOf(m), 10)

// 创建一个新申请的元素类型为typ，长度len容量cap的slice类型的Value值
reflect.MakeSlice(reflect.ValueOf(sl).Type(), reflect.ValueOf(sl).Len(), reflect.ValueOf(sl).Cap())

// 返回元素类型为t、方向为dir的channel类型的Type
// 运行时GC强制将通道的元素类型的大小限定为64kb
// 如果t的尺寸大于或等于该限制，本函数将会panic
reflect.ChanOf(reflect.BothDir, reflect.TypeOf(c))

// 返回给定参数和结果类型的func类型的Type
// 例如，如果 k 表示 int 并且 e 表示字符串，则 FuncOf([]Type{k}, []Type{e}, false) 表示 func(int) string
// 可变参数variadic 控制函数是否可变。如果len(in)-1 不代表切片并且可变参数为true，则 FuncOf 会panic
reflect.FuncOf([]reflect.Type{reflect.TypeOf(15)}, []reflect.Type{reflect.TypeOf("Hello")}, false)



// 使用给定的键和元素类型返回map类型的Type
// 例如，如果 k 表示 int 并且 e 表示字符串，则 MapOf(k, e) 表示 map[int]string
// 如果键类型不是有效的映射键类型（也就是说，如果它不执行 Go 的==运算符），则 MapOf会panic
reflect.MapOf(reflect.TypeOf(15), reflect.TypeOf("Hello"))

// 使用给定的计数和元素类型返回数组类型的Type
// 例如，如果 t 表示 int ，则 ArrayOf(5, t) 表示 [5]int
// 如果生成的类型会比可用的地址空间大，ArrayOf 会panic
reflect.ArrayOf(5, reflect.TypeOf(15))

// 返回元素类型为 t 的slice类型的Type
// 例如，如果 t 表示 int ， SliceOf(t) 表示 []int
reflect.SliceOf(reflect.ValueOf(sl).Type())

// 返回包含字段的结构类型的Type
// 偏移量和索引字段被忽略和计算，就像编译器一样
// StructOf 目前不会为嵌入字段生成封装器方法。未来版本中可能会取消此限制
reflect.StructOf([]reflect.StructField{
{
Name: "Height",
Type: reflect.TypeOf(float64(0)),
Tag:  `json:"height"`,
},
{
Name: "Age",
Type: reflect.TypeOf(int(0)),
Tag:  `json:"age"`,
},
})
}

func example() {
typ := reflect.StructOf([]reflect.StructField{
{
Name: "Height",
Type: reflect.TypeOf(float64(0)),
Tag:  `json:"height"`,
},
{
Name: "Age",
Type: reflect.TypeOf(int(0)),
Tag:  `json:"age"`,
},
})

// 返回一个Value类型值，该值持有一个指向类型为typ的新申请的零值的指针，返回值的Type为PtrTo(typ)
reflect.New(typ)

// 返回类型t的指针的类型
reflect.PtrTo(typ)

// 返回一个持有类型typ的零值的Value
// 注意持有零值的Value和Value零值是两回事
// Value零值表示不持有任何值，例如Zero(TypeOf(42))返回一个Kind为Int、值为0的Value
// Zero的返回值不能设置也不会寻址
reflect.Zero(typ)

// 返回一个函数，它交换提供的 slice 中的元素
// 如果提供的接口不是切片，Swapper会panic
sl := []int{1, 5, 9, 3, 7}
reflect.Swapper(sl)

// 将src中的值拷贝到dst，直到src被耗尽或者dst被装满，要求这二者都是slice或array，且元素类型相同
var dst []byte
var src = []byte("Hello World!")
reflect.Copy(reflect.ValueOf(dst), reflect.ValueOf(src))

// 用来判断两个值是否深度一致：除了类型相同；在可以时（主要是基本类型）会使用==；但还会比较array、slice的成员，map的键值对，结构体字段进行深入比对
// map的键值对，对键只使用==，但值会继续往深层比对，可以正确处理循环的类型
// 函数类型只有都会nil时才相等；空切片不等于nil切片；还会考虑array、slice的长度、map键值对数
reflect.DeepEqual("1", 1)
}
######################################################################################
D:\go\go\go标准库示例\regexp\regexp.go

package main
import (
"fmt"
"log"
"regexp"
"strings"
)

// regexp 包实现正则表达式搜索
// 接受的正则表达式的语法与 Perl，Python 和其他语言使用的通用语法相同。更准确地说，它是  RE2 接受的语法，并在https://golang.org/s/re2syntax中进行了描述，\C除外
// 有关语法的概述，请运行 `go doc regexp/syntax`
// 所有字符都是 UTF-8 编码的代码点
func main() {
// 简单匹配示例
exampleMatch()

// 转义特殊字符
exampleQuoteMeta()

// 匹配示例
exampleCompile()

// 最长匹配示例
exampleCompilePOSTIX()
exampleSubMatch()

// 匹配追加
exampleExpand()
}

func exampleMatch() {
data := "Hello World![test]"
pattern := `\d*`

// 匹配检查文本正则表达式是否与字节片匹配。更复杂的查询需要使用 Compile 和完整的 Regexp 接口
ok, err := regexp.Match(pattern, []byte(data))
if err != nil {
log.Fatal(err)
}
fmt.Println(ok)

// 检查文本正则表达式是否与 RuneReader 读取的文本匹配。更复杂的查询需要使用 Compile 和完整的 Regexp 接口
ok, err = regexp.MatchReader(pattern, strings.NewReader(data))
if err != nil {
log.Fatal(err)
}
fmt.Println(ok)

// 检查文本正则表达式是否匹配字符串。更复杂的查询需要使用 Compile 和完整的 Regexp 接口
ok, err = regexp.MatchString(pattern, data)
if err != nil {
log.Fatal(err)
}
fmt.Println(ok)
}

func exampleQuoteMeta() {
// 返回一个字符串，它引用参数文本中的所有正则表达式元字符； 返回的字符串是一个匹配文本文本的正则表达式。例如，QuoteMeta（[foo]）返回\[foo\]
// 特殊字符有：\.+*?()|[]{}^$
// 这些字符用于实现正则语法，所以当作普通字符使用时需要转换
str := regexp.QuoteMeta(`Escaping symbols like: .+*?()|[]{}^$`)
fmt.Println(str)
}

func exampleCompile() {
data := "Hello foo!"

// 编译解析一个正则表达式，并且如果成功返回一个可以用来匹配文本的 Regexp 对象
r, err := regexp.Compile(`foo.?`)
if err != nil {
log.Fatal(err)
}

// 等同于Compile。但如果表达式不能被解析就会panic
r = regexp.MustCompile(`foo(.?)`)

// 匹配字符串
fmt.Println(r.MatchString(data))

// 匹配字节切片
fmt.Println(r.Match([]byte(data)))

// 匹配文本
fmt.Println(r.MatchReader(strings.NewReader(data)))

// 返回正则表达式
fmt.Println("正则表达式：", r.String())

// 查找字节切片，返回第一个匹配的内容
fmt.Printf("%s\n", r.Find([]byte(data)))

// 查找字节切片，返回第一个匹配的位置
// [起始位置, 结束位置]
fmt.Println(r.FindIndex([]byte(data)))

// 查找字符串，返回第一个匹配的内容
fmt.Println(r.FindString(data))

// 查找字符串，返回第一个匹配的位置
// [起始位置, 结束位置]
fmt.Println(r.FindStringIndex(data))

// 查找字节切片，返回所有匹配的内容
// 只查找前 n 个匹配项，如果 n < 0，则查找所有匹配项
fmt.Printf("%q\n", r.FindAll([]byte(data), -1))

// 查找字节切片，返回所有匹配的位置
// 只查找前 n 个匹配项，如果 n < 0，则查找所有匹配项
// [[起始位置, 结束位置], [起始位置, 结束位置]...]
fmt.Println(r.FindAllIndex([]byte(data), -1))

// 查找字符串，返回所有匹配的内容
// 只查找前 n 个匹配项，如果 n < 0，则查找所有匹配项
fmt.Println(r.FindAllString(data, -1))

// 查找字符串，返回所有匹配的位置
// 只查找前 n 个匹配项，如果 n < 0，则查找所有匹配项
// [[起始位置, 结束位置], [起始位置, 结束位置]...]
fmt.Println(r.FindAllStringIndex(data, -1))

// 查找文本，返回第一个匹配的位置
// [起始位置, 结束位置]
fmt.Println(r.FindReaderIndex(strings.NewReader(data)))

// 查找字符串，以匹配项为分割符 分割成多个子串
// 最多分割出 n 个子串，第 n 个子串不再进行分割
// 如果 n < 0，则分割所有子串
// 返回分割后的子串列表
fmt.Println(r.Split(data, -1))

// 返回所有匹配项都共同拥有的前缀（去除可变元素）
// prefix：共同拥有的前缀
// complete：如果 prefix 就是正则表达式本身，则返回 true，否则返回 false
fmt.Println(r.LiteralPrefix())

// 在 src 中搜索匹配项，并替换为 repl 指定的内容
// 全部替换，并返回替换后的结果
fmt.Printf("%s\n", r.ReplaceAll([]byte(data), []byte("World!")))
fmt.Printf("%s\n", r.ReplaceAllString(data, "World!"))

// 在 src 中搜索匹配项，并替换为 repl 指定的内容
// 如果 repl 中有“分组引用符”（$1、$name），则将“分组引用符”当普通字符处理
// 全部替换，并返回替换后的结果
fmt.Printf("%s\n", r.ReplaceAllLiteral([]byte(data), []byte("$World")))
fmt.Printf("%s\n", r.ReplaceAllLiteralString(data, "$World"))

// 在 src 中搜索匹配项，然后将匹配的内容经过 repl方法 处理后，替换 src 中的匹配项
// 如果 repl 的返回值中有“分组引用符”（$1、$name），则将“分组引用符”当普通字符处理
// 全部替换，并返回替换后的结果
fmt.Printf("%s\n", r.ReplaceAllFunc([]byte(data), func(b []byte) []byte { return []byte("World!") }))
fmt.Printf("%s\n", r.ReplaceAllStringFunc(data, func(s string) string { return "World!" }))

// 切换到贪婪模式
// 正则标记“非贪婪模式”(?U)，如`(?U)H[\w\s]+o`
r.Longest()
}

func exampleCompilePOSTIX() {
data := "Hello World!"

// CompilePOSIX 的作用和 Compile 一样
// 不同的是，CompilePOSIX 使用 POSIX 语法，
// 同时，它采用最左最长方式搜索，
// 而 Compile 采用最左最短方式搜索
// POSIX 语法不支持 Perl 的语法格式：\d、\D、\s、\S、\w、\W
r, err := regexp.CompilePOSIX(`foo.?`)
if err != nil {
log.Fatal(err)
}

// 等同于CompilePOSIX。但如果表达式不能被解析就会panic
r = regexp.MustCompilePOSIX(`foo.?`)
fmt.Println(r.MatchString(data))
// 其它用法参见Compile
}

func exampleSubMatch() {
data := "seafood fool"
r := regexp.MustCompile(`foo(.?)`)

// 统计正则表达式中的分组个数（不包括“非捕获的分组”）
fmt.Println(r.NumSubexp())

// 返回分组名称列表，未命名的分组返回空字符串
// 返回值[0] 为整个正则表达式的名称
// 返回值[1] 是分组 1 的名称
// 返回值[2] 是分组 2 的名称
fmt.Println(r.SubexpNames())

// 查找字节切片，返回第一个匹配的内容
// 同时返回子表达式匹配的内容
// [[完整匹配项], [子匹配项], [子匹配项], ...]
fmt.Printf("%s\n", r.FindSubmatch([]byte(data)))

// 查找字节切片，返回第一个匹配的位置
// 同时返回子表达式匹配的位置
// [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...]
fmt.Println(r.FindSubmatchIndex([]byte(data)))

// 查找字符串，返回第一个匹配的内容
// 同时返回子表达式匹配的内容
// [[完整匹配项], [子匹配项], [子匹配项], ...]
fmt.Println(r.FindStringSubmatch(data))

// 查找字符串，返回第一个匹配的位置
// 同时返回子表达式匹配的位置
// [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...]
fmt.Println(r.FindStringSubmatchIndex(data))

// 查找字节切片，返回所有匹配的内容
// 同时返回子表达式匹配的内容
// [ [[完整匹配项], [子匹配项], [子匹配项], ...], [[完整匹配项], [子匹配项], [子匹配项], ...] ]
fmt.Printf("%q\n", r.FindAllSubmatch([]byte(data), -1))

// 查找字节切片，返回所有匹配的位置
// 同时返回子表达式匹配的位置
// 只查找前 n 个匹配项，如果 n < 0，则查找所有匹配项
// [ [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...], [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...]... ]
fmt.Println(r.FindAllSubmatchIndex([]byte(data), -1))

// 查找字符串，返回所有匹配的内容
// 同时返回子表达式匹配的内容
// [ [[完整匹配项], [子匹配项], [子匹配项], ...], [[完整匹配项], [子匹配项], [子匹配项], ...] ]
fmt.Println(r.FindAllStringSubmatch(data, -1))

// 查找字节切片，返回所有匹配的位置
// 同时返回子表达式匹配的位置
// 只查找前 n 个匹配项，如果 n < 0，则查找所有匹配项
// [ [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...], [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...]... ]
fmt.Println(r.FindAllStringSubmatchIndex(data, -1))

// 查找文本，返回第一个匹配的位置
// 同时返回子表达式匹配的位置
// [完整项起始, 完整项结束, 子项起始, 子项结束, 子项起始, 子项结束, ...]
fmt.Println(r.FindReaderSubmatchIndex(strings.NewReader(data)))
}

// 追加
func exampleExpand() {
content := `
	# comment line
	option1: value1
	option2: value2
	# another comment line
	option3: value3
`
pattern := regexp.MustCompile(`(?m)(?P<key>\w+):\s+(?P<value>\w+)$`)
template := "$key=$value\n"
var result []byte
var resultStr []byte
for _, s := range pattern.FindAllSubmatchIndex([]byte(content), -1) {
// 将 template 的内容经过处理后，追加到 dst 的尾部
// template 中要有 $1、$2、${name1}、${name2} 这样的“分组引用符”
// match 是由 FindSubmatchIndex 方法返回的结果，里面存放了各个分组的位置信息
// 如果 template 中有“分组引用符”，则以 match 为标准，
// 在 src 中取出相应的子串，替换掉 template 中的 $1、$2 等引用符号。
result = pattern.Expand(result, []byte(template), []byte(content), s)
}

fmt.Println(string(result))
for _, s := range pattern.FindAllStringSubmatchIndex(content, -1) {
// 同Expand类似
resultStr = pattern.ExpandString(resultStr, template, content, s)
}
fmt.Println(string(resultStr))
}
######################################################################################
D:\go\go\go标准库示例\rutime\runtime-debug.go

package main

import (
"fmt"
"log"
"os"
"runtime"
"runtime/debug"
"time"
)

// debug包提供了程序在运行时进行调试的功能
func main() {
// 强制进行一次垃圾收集，以释放尽量多的内存回操作系统。（即使没有调用，运行时环境也会在后台任务里逐渐将内存释放给系统）
debug.FreeOSMemory()

// 返回嵌入在运行二进制文件中的构建信息
// 该信息仅在使用模块支持构建的二进制文件中可用
if info, ok := debug.ReadBuildInfo(); ok {

// main包路径
fmt.Println(info.Path)

// module信息
fmt.Println(info.Main)

// module依赖
fmt.Println(info.Deps)
}

// 设置垃圾回收百分比
exampleGCPercent()

// 设置被单个go协程调用栈可使用内存值
exampleSetMaxStack()

// 设置go程序可以使用的最大操作系统线程数
exampleSetMaxThreads()

// 设置程序请求运行是只触发panic,而不崩溃
exampleSetPanic()

// 垃圾收集信息
exampleStats()

// 将内存分配堆和其中对象的描述写入文件中
exampleHeapDump()

// 获取go协程调用栈踪迹
exampleStack()
}

func exampleGCPercent() {
// 设定垃圾收集的目标百分比
// 当新申请的内存大小占前次垃圾收集剩余可用内存大小的比率达到设定值时，就会触发垃圾收集
// SetGCPercent返回之前的设定。初始值为环境变量GOGC的值；如果没有设置该环境变量，初始值为100
// percent参数如果是负数值，会关闭垃圾收集
fmt.Println(debug.SetGCPercent(1))

// 初始化切片
var dic = make([]byte, 100, 100)

// 将x的终止器设置为f
// 当垃圾收集器发现一个不能接触的（即引用计数为零，程序中不能再直接或间接访问该对象）具有终止器的块时，它会清理该关联（对象到终止器）并在独立go程调用f(x)
// 这使x再次可以接触，但没有了绑定的终止器。如果SetFinalizer没有被再次调用，下一次垃圾收集器将视x为不可接触的，并释放x
// SetFinalizer(x, nil)会清理任何绑定到x的终止器
runtime.SetFinalizer(&dic, func(dic *[]byte) {
fmt.Println("内存回收1")
})

// 立即回收
runtime.GC()
var s = make([]byte, 100, 100)
runtime.SetFinalizer(&s, func(dic *[]byte) {
fmt.Println("内存回收2")
})

d := make([]byte, 300, 300)
for index, _ := range d {
d[index] = 'a'
}

fmt.Println(d)
time.Sleep(time.Second)
}

func exampleSetMaxStack() {
// 设置被单个go协程调用栈可使用的内存最大值
// 修改该函数设置值为1，再次运行 exampleSetMaxStack()即可看到效果
debug.SetMaxStack(102400)
for i := 0; i < 10; i++ {
go func() {
fmt.Println(1)
}()
}
time.Sleep(time.Second)
}

func exampleSetMaxThreads() {
// 置go程序可以使用的最大操作系统线程数
// 如果程序试图使用超过该限制的线程数，就会导致程序崩溃
// SetMaxThreads返回之前的设置，初始设置为10000个线程
// 主要用于限制程序无限制的创造线程导致的灾难。目的是让程序在干掉操作系统之前，先干掉它自己
debug.SetMaxThreads(10)

go func() {
fmt.Println("Hello World!")
}()
time.Sleep(time.Second)
}

func exampleSetPanic() {
go func() {
defer func() { recover() }()

// 控制程序在不期望（非nil）的地址出错时的运行时行为
// 这些错误一般是因为运行时内存破坏的bug引起的，因此默认反应是使程序崩溃
// 使用内存映射的文件或进行内存的不安全操作的程序可能会在非nil的地址出现错误；SetPanicOnFault允许这些程序请求运行时只触发一个panic，而不是崩溃
// SetPanicOnFault只用于当前的go程。它返回之前的设置
fmt.Println(debug.SetPanicOnFault(true))
var s *int = nil
*s = 34
}()

time.Sleep(time.Second)
fmt.Println("ddd")
}

func exampleStats() {
// 初始化切片
data := make([]byte, 1000, 1000)
println(data)

// 回收
runtime.GC()

// 声明一个GCStats，用于收集了近期垃圾收集的信息
var stats debug.GCStats

// 将垃圾收集信息填入stats里
debug.ReadGCStats(&stats)

// 垃圾收集的次数
fmt.Println(stats.NumGC)

// 最近一次垃圾收集的时间
fmt.Println(stats.LastGC)

// 每次暂停收集垃圾的消耗的时间
fmt.Println(stats.Pause)

// 所有暂停收集垃圾消耗的总时间
fmt.Println(stats.PauseTotal)

// 暂停结束时间历史记录，最近的第一个
fmt.Println(stats.PauseEnd)
}

func exampleHeapDump() {

// 打开文件
f, _ := os.OpenFile("testdata/debug_heapDump.txt", os.O_RDWR|os.O_CREATE, 0666)

// 返回与文件f对应的整数类型的Unix文件描述符
fd := f.Fd()

// 将内存分配堆和其中对象的描述写入给定文件描述符fd指定的文件
debug.WriteHeapDump(fd)

data := make([]byte, 10, 10)
println(data)
runtime.GC()

if err := f.Close(); err != nil {
log.Fatal(err)
}
}

func exampleStack() {
go func() {
// 返回格式化的go程的调用栈踪迹
// 对于每一个调用栈，它包括原文件的行信息和PC值；对go函数还会尝试获取调用该函数的函数或方法，及调用所在行的文本
fmt.Println(string(debug.Stack()))

// 将Stack返回信息打印到标准错误输出
// debug.PrintStack()
}()

time.Sleep(time.Second)
}
######################################################################################
D:\go\go\go标准库示例\rutime\runtime-pprof.go

package main

import (
"fmt"
"log"
"os"
"runtime"
"runtime/pprof"
)

// pprof包以pprof可视化工具期望的格式书写运行时剖面数据
// 采集程序的运行数据进行分析，使用 'go tool pprof' 命令进行分析
func main() {

// 创建pprof文件
// 使用 "go tool pprof testdata/test.prof" 进入，如 使用top查看数据，web生成svg文件
f, err := os.Create("testdata/test.prof")
if err != nil {
log.Fatal(err)
}

// 设置CPU profile记录的速率为平均每秒hz次
// 如果hz<=0，SetCPUProfileRate会关闭profile的记录。如果记录器在执行，该速率必须在关闭之后才能修改
runtime.SetCPUProfileRate(10000)

// 为当前进程开启CPU profile
// 在分析时，分析报告会缓存并写入到w中。若分析已经开启，StartCPUProfile就会返回错误
if err := pprof.StartCPUProfile(f); err != nil {
log.Fatal(err)
}

// 停止当前的CPU profile（如果有）
// 只会在所有的分析报告写入完毕后才会返回
defer pprof.StopCPUProfile()

// 下面写自己的程序
for i := 0; i < 30; i++ {
// 递归实现的斐波纳契数列
num := fibonacci(i)
fmt.Println(num)
}
}

func fibonacci(num int) int {

if num < 2 {

return 1

}
return fibonacci(num-1) + fibonacci(num-2)
}

######################################################################################
D:\go\go\go标准库示例\rutime\runtime-trace.go

package main

import (
"fmt"
"log"
"os"
"runtime/trace"
)

// 执行追踪器
// 跟踪器捕获各种各样的执行事件，如 goroutine 创建/阻塞/解锁，系统调用进入/退出/块，GC 相关事件，堆大小变化，处理器启动/停止等，并将它们以紧凑的形式写入 io.Writer 中
// 大多数事件都会捕获精确的纳秒精度时间戳和堆栈跟踪。跟踪可以稍后使用 'go tool trace' 命令进行分析

func main() {
// 创建trace.out文件
// 跟踪完毕后可以使用 "go tool trace testdata/trace.out" 命令分析
f, err := os.Create("testdata/trace.out")
if err != nil {
log.Fatalf("failed to create trace output file: %v", err)
}

defer func() {
if err := f.Close(); err != nil {
log.Fatalf("failed to close trace file: %v", err)
}
}()

// 启用当前程序的跟踪
// 跟踪时，跟踪将被缓冲并写入 w
// 如果跟踪已启用，则启动将返回错误
if err := trace.Start(f); err != nil {
log.Fatalf("failed to start trace: %v", err)
}
// 停止当前跟踪，如果有的话。在完成跟踪的所有写入后，仅停止返回
defer trace.Stop()

// 下面写自己的程序
traceTest()
}

func traceTest() {
fmt.Printf("this function will be traced\n")
}
######################################################################################
D:\go\go\go标准库示例\rutime\runtime.go

package main

import (
"fmt"
"runtime"
"strings"
)

// runtime包提供和go运行时环境的互操作，如控制go程的函数
// 它也包括用于reflect包的低层次类型信息
func main() {
// 基础
example()

// 显示调用过程
exampleFrames()
}

func example() {
// 返回Go的根目录。如果存在GOROOT环境变量，返回该变量的值；否则，返回创建Go时的根目录
fmt.Println(runtime.GOROOT())

// 返回Go的版本字符串。它要么是递交的hash和创建时的日期；要么是发行标签如"go1.3"
fmt.Println(runtime.Version())

// 返回本地机器的逻辑CPU个数
fmt.Println(runtime.NumCPU())

// 返回当前进程执行的cgo调用次数
fmt.Println(runtime.NumCgoCall())

// 返回当前存在的Go程数
fmt.Println(runtime.NumGoroutine())

// 执行一次垃圾回收
runtime.GC()

// 设置可同时执行的最大CPU数，并返回先前的设置
// 若 n < 1，它就不会更改当前设置
// 本地机器的逻辑CPU数可通过 NumCPU 查询。本函数在调度程序优化后会去掉
runtime.GOMAXPROCS(2)

go func() {
fmt.Println("Start Goroutine1")

// 终止调用它的go程。其它go程不会受影响。Goexit会在终止该go程前执行所有defer的函数。
// 在程序的main go程调用本函数，会终结该go程，而不会让main返回
// 因为main函数没有返回，程序会继续执行其它的go程
// 如果所有其它go程都退出了，程序会panic
runtime.Goexit()

fmt.Println("End Goroutine1")
}()

go func() {
// 使当前go程放弃处理器，以让其它go程运行。它不会挂起当前go程，因此当前go程未来会恢复执行
runtime.Gosched()
fmt.Println("Start Goroutine2")
fmt.Println("End Goroutine2")
}()

go func() {
// 将调用的go程绑定到它当前所在的操作系统线程
// 除非调用的go程退出或调用UnlockOSThread，否则它将总是在该线程中执行，而其它go程则不能进入该线程
runtime.LockOSThread()
fmt.Println("Start Goroutine3")
fmt.Println("End Goroutine3")

// 将调用的go程解除和它绑定的操作系统线程
// 若调用的go程未调用LockOSThread，UnlockOSThread不做操作
runtime.UnlockOSThread()
}()
}

func exampleFrames() {
c := func() {

// 初始化一个长度为10的整数切片
pc := make([]uintptr, 10)

// 把当前go程调用栈上的调用栈标识符填入切片pc中，返回写入到pc中的项数
// 实参skip为开始在pc中记录之前所要跳过的栈帧数，0表示Callers自身的调用栈，1表示Callers所在的调用栈
n := runtime.Callers(0, pc)
if n == 0 {

return

}

// 截取有效部分
pc = pc[:n]

// 获取被调用方返回的PC值切片，并准备返回 函数/文件/行 信息
// 在完成帧处理之前，不要更改切片
frames := runtime.CallersFrames(pc)

for {
// 返回下一个调用者的帧信息
// 如果 more为false，则无下一个（Frame 值有效）
frame, more := frames.Next()

// 判断文件名是否包含 "runtime/" 字符串
if !strings.Contains(frame.File, "runtime/") {
break
}
fmt.Printf("- more:%v | %s\n", more, frame.Function)
if !more {
break
}
}
}
b := func() { c() }
a := func() { b() }
a()
}
######################################################################################
D:\go\go\go标准库示例\sort\sort.go

package main
import (
"fmt"
"sort"
)

// sort包提供了排序切片和用户自定义数据集的函数
func main() {
// 对任意切片排序，函数实现版
example()

// 对任意切片排序，函数实现版，推荐使用
exampleStable()

// 对任意 函数实现版 切片类型 反向排序
exampleReverse()

// []string排序
exampleString()

// []int排序
exampleInt()

// []float64排序
exampleFloat()

// 对任意切片排序
exampleSlice()

// 对任意切片排序，推荐使用
exampleSliceStable()
}

type People struct {
Name string
Age  int
}

type Peoples []People
func (p Peoples) Len() int           { return len(p) }
func (p Peoples) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
func (p Peoples) Less(i, j int) bool { return p[i].Age < p[j].Age } // 按age递增排序

func example() {
// 声明一个简单的结构体
peoples := Peoples{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}

// 任意切片排序，但是切片必须包含Len(),Swap(),Less()方法
sort.Sort(peoples)
fmt.Println(peoples)

// 检查是否已经被排序
fmt.Println(sort.IsSorted(peoples))
}

func exampleStable() {
// 声明一个简单的结构体
peoples := Peoples{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}

// 任意切片排序，但是切片必须包含Len(),Swap(),Less()方法
sort.Stable(peoples)
fmt.Println(peoples)

// 检查是否已经被排序
fmt.Println(sort.IsSorted(peoples))
}

func exampleReverse() {
// 声明一个简单的结构体
peoples := Peoples{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}

// 包装一个Interface接口并返回一个新的Interface接口，对该接口排序可生成递减序列
p := sort.Reverse(peoples)

// 排序
sort.Sort(p)
fmt.Println(peoples)
}

func exampleString() {
s := []string{"Go", "Bravo", "Gopher", "Alpha", "Grin", "Delta"}

// 排序为递增顺序
sort.Strings(s)
fmt.Println(s)

s = []string{"Go", "Bravo", "Gopher", "Alpha", "Grin", "Delta"}
// 排序为递增顺序
// 将[]string指定为sort.StringSlice类型并排序，类型内部实现了排序方法
sort.Sort(sort.StringSlice(s))
fmt.Println(s)

// 检查是否已排序为递增顺序
fmt.Println(sort.StringsAreSorted(s))

// 返回x在a中应该存在的位置，无论a中是否存在a中
// 在递增顺序的a中搜索x，返回x的索引。如果查找不到，返回值是x应该插入a的位置（以保证a的递增顺序），返回值可以是len(a)
index := sort.SearchStrings(s, "Hello")
fmt.Println(index)
}

func exampleInt() {
s := []int{5, 2, 6, 3, 1, 4}

// 排序为递增顺序
sort.Ints(s)
fmt.Println(s)

s = []int{5, 2, 6, 3, 1, 4}
// 排序为递增顺序
// 将[]int指定为sort.IntSlice类型并排序，类型内部实现了排序方法
sort.Sort(sort.IntSlice(s))
fmt.Println(s)

// 检查是否已排序为递增顺序
fmt.Println(sort.IntsAreSorted(s))

// 返回x在a中应该存在的位置，无论a中是否存在a中
// 在递增顺序的a中搜索x，返回x的索引。如果查找不到，返回值是x应该插入a的位置（以保证a的递增顺序），返回值可以是len(a)
index := sort.SearchInts(s, 5)
fmt.Println(index)
}

func exampleFloat() {
s := []float64{5.2, -1.3, 0.7, -3.8, 2.6}
// 排序为递增顺序
sort.Float64s(s)
fmt.Println(s)

s = []float64{5.2, -1.3, 0.7, -3.8, 2.6}
// 将[]float64指定为sort.Float64Slice类型并排序，类型内部实现了排序方法
sort.Sort(sort.Float64Slice(s))
fmt.Println(s)

// 检查是否已排序为递增序列
fmt.Println(sort.Float64sAreSorted(s))

// 返回x在a中应该存在的位置，无论a中是否存在a中
// 在递增顺序的a中搜索x，返回x的索引。如果查找不到，返回值是x应该插入a的位置（以保证a的递增顺序），返回值可以是len(a)
index := sort.SearchFloat64s(s, 2)
fmt.Println(index)
}

func exampleSlice() {
// 声明一个简单的结构体
people := []struct {
Name string
Age  int
}{
{"Gopher", 7},
{"Alice", 55},
{"Vera", 24},
{"Bob", 75},
}

// 对切片自定义进行排序
// 该接口不能保证是稳定的。对于稳定类型，使用SliceStable
// 如果提供的接口不是切片，则函数将终止
sort.Slice(people, func(i, j int) bool {
return people[i].Name < people[j].Name
})
fmt.Println("By name:", people)
sort.Slice(people, func(i, j int) bool {
return people[i].Age < people[j].Age
})
fmt.Println("By age:", people)
}

func exampleSliceStable() {
// 声明一个简单的结构体
people := []struct {
Name string
Age  int
}{
{"Alice", 25},
{"Elizabeth", 75},
{"Alice", 75},
{"Bob", 75},
{"Alice", 75},
{"Bob", 25},
{"Colin", 25},
{"Elizabeth", 25},
}

// 对提供的切片进行排序，同时保持相等元素的原始顺序
// 如果提供的接口不是切片，则函数将终止
sort.SliceStable(people, func(i, j int) bool { return people[i].Name < people[j].Name })
fmt.Println("By name:", people)
sort.SliceStable(people, func(i, j int) bool { return people[i].Age < people[j].Age })
fmt.Println("By age,name:", people)
}
######################################################################################
D:\go\go\go标准库示例\strconv\strconv.go

package main
import (
"fmt"
"log"
"strconv"
)

// strconv包实现了基本数据类型和其字符串表示的相互转换
func main() {
// bool操作
exampleBool()

// float操作
exampleFloat()

// int操作
exampleInt()

// uint操作
exampleUint()

// 转义操作
exampleQuote()

// 反转义操作
exampleUnquote()

// 数字解析错误操作
exampleNumError()
}

func exampleBool() {
// bool转string
s := strconv.FormatBool(true)
fmt.Printf("%T, %v\n", s, s)

// string转bool
bl, err := strconv.ParseBool(s)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T, %v\n", bl, bl)

// 添加string类型的bool值
b := []byte("bool:")
b = strconv.AppendBool(b, true)
fmt.Println(string(b))
}

func exampleFloat() {
v := 3.1415926535

// float32转string
// fmt表示格式：'f'（-ddd.dddd）、'b'（-ddddp±ddd，指数为二进制）、'e'（-d.dddde±dd，十进制指数）、'E'（-d.ddddE±dd，十进制指数）、'g'（指数很大时用'e'格式，否则'f'格式）、'G'（指数很大时用'E'格式，否则'f'格式）
// prec控制精度（排除指数部分）：对'f'、'e'、'E'，它表示小数点后的数字个数；对'g'、'G'，它控制总的数字个数。如果prec 为-1，则代表使用最少数量的、但又必需的数字来表示f
s32 := strconv.FormatFloat(float64(v), 'f', -1, 32)
fmt.Printf("%T, %v\n", s32, s32)

// float64转string
s64 := strconv.FormatFloat(v, 'f', -1, 64)
fmt.Printf("%T, %v\n", s64, s64)

// string转float32
if s, err := strconv.ParseFloat(s32, 32); err == nil {
s1 := float32(s)
fmt.Printf("%T, %v\n", s1, s1)
}

// string转float64
if s, err := strconv.ParseFloat(s64, 64); err == nil {
fmt.Printf("%T, %v\n", s, s)
}

// 添加string类型的float32值
b32 := []byte("float32:")
b32 = strconv.AppendFloat(b32, v, 'f', -1, 32)
fmt.Println(string(b32))

// 添加string类型的float64值
b64 := []byte("float64:")
b64 = strconv.AppendFloat(b64, v, 'f', -1, 64)
fmt.Println(string(b64))
}

func exampleInt() {
v := 12

// int转string
s := strconv.Itoa(v)
fmt.Printf("%T, %v\n", s, s)

// string转int
i, err := strconv.Atoi(s)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T, %v\n", i, i)

// int64转十进制string
// base 必须在2到36之间
s = strconv.FormatInt(int64(v), 10)
fmt.Printf("%T, %v\n", s, s)

// 十进制string转int64
i64, err := strconv.ParseInt(s, 10, 64)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T, %v\n", i64, i64)

// 添加string类型的int十进制值
b10 := []byte("int (base 10):")
b10 = strconv.AppendInt(b10, -42, 10)
fmt.Println(string(b10))

// 添加string类型的int十六进制值
b16 := []byte("int (base 16):")
b16 = strconv.AppendInt(b16, -42, 16)
fmt.Println(string(b16))
}

func exampleUint() {
v := uint64(42)

// uint64转十进制string
s := strconv.FormatUint(v, 10)
fmt.Printf("%T, %v\n", s, s)

// 十进制string转uint64
u, err := strconv.ParseUint(s, 10, 64)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%T, %v\n", u, u)

// 添加string类型的uint十进制值
b10 := []byte("uint (base 10):")
b10 = strconv.AppendUint(b10, 42, 10)
fmt.Println(string(b10))
}

func exampleQuote() {
v := `"Fran & Freddie's Diner	☺"`
vr := '☺'

// 判断字符串 s 是否可以表示为一个单行的“反引号”字符串
// 字符串中不能含有控制字符（除了 \t）和“反引号”字符，否则返回 false
// 判断是否可以转义
ok := strconv.CanBackquote(v)
fmt.Println(ok)

// 返回字符串s在go语法下的双引号字面值表示，控制字符、不可打印字符会进行转义。（如\t，\n，\xFF，\u0100）
// 转义字符串
s := strconv.Quote(v)
fmt.Println(s)

// 返回字符串s在go语法下的双引号字面值表示，控制字符和不可打印字符、非ASCII字符会进行转义
// 转义字符串为ASCII
sa := strconv.QuoteToASCII(v)
fmt.Println(sa)

// 判断 Unicode 字符 r 是否是一个可显示的字符
// 可否显示并不是你想象的那样，比如空格可以显示，而\t则不能显示
// 判断rune是否可以转义
rok := strconv.IsPrint(vr)
fmt.Println(rok)

// 返回字符r在go语法下的单引号字面值表示，控制字符、不可打印字符会进行转义。（如\t，\n，\xFF，\u0100）
// rune转string
sr := strconv.QuoteRune(vr)
fmt.Println(sr)

// 返回字符串s在go语法下的双引号字面值表示，控制字符和不可打印字符、非ASCII字符会进行转义
// rune转ASCII
sra := strconv.QuoteRuneToASCII(vr)
fmt.Println(sra)

// 将字符串转义并添加
b := strconv.AppendQuote([]byte("quote:"), `"Fran & Freddie's Diner"`)
fmt.Println(string(b))

// 将字符串转义为ASCII并添加
ba := strconv.AppendQuoteToASCII([]byte("quote (ascii):"), v)
fmt.Println(string(ba))

// 将rune转义并添加
br := strconv.AppendQuoteRune([]byte("rune:"), vr)
fmt.Println(string(br))

// 将rune转义为ASCII并添加
bra := strconv.AppendQuoteRuneToASCII([]byte("rune (ascii):"), vr)
fmt.Println(string(bra))
}

func exampleUnquote() {
// 与Quote相反
// 将“带引号的字符串” s 转换为常规的字符串（不带引号和转义字符）
// s 可以是“单引号”、“双引号”或“反引号”引起来的字符串（包括引号本身）
// 如果 s 是单引号引起来的字符串，则返回该该字符串代表的字符
s, err := strconv.Unquote("\"The string must be either double-quoted\"")
fmt.Printf("%q, %v\n", s, err)

// 将 转义后的字符串s 中的第一个字符“取消转义”并解码
// 参数quote：字符串使用的“引号符”（用于对引号符“取消转义”）
// 参数 quote 为“引号符”
// value：解码后的字符；multibyte：value 是否为多字节字符；tail： 字符串s 除去 value 后的剩余部分；error：返回语法错误
// 如果设置为单引号，则 s 中允许出现 \' 字符，不允许出现单独的 ' 字符
// 如果设置为双引号，则 s 中允许出现 \" 字符，不允许出现单独的 " 字符
// 如果设置为 0，则不允许出现 \' 或 \" 字符，可以出现单独的 ' 或 " 字符
v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"')
if err != nil {
log.Fatal(err)
}
fmt.Println("value:", string(v))
fmt.Println("multibyte:", mb)
fmt.Println("tail:", t)
}

func exampleNumError() {
str := "Not a number"
// 将一个不是数字的字符串解析为float类型
if _, err := strconv.ParseFloat(str, 64); err != nil {

// error 定义为 *strconv.NumError类型
e := err.(*strconv.NumError)

// 失败的函数（ParseBool、ParseInt、ParseUint、ParseFloat）
fmt.Println("Func:", e.Func)

// 输入的字符串
fmt.Println("Num:", e.Num)

// 失败的原因（ErrRange、ErrSyntax）
fmt.Println("Err:", e.Err)
fmt.Println(err)
}
}
######################################################################################
D:\go\go\go标准库示例\strings\strings.go

package main
import (
"fmt"
"strings"
"unicode"
)

// strings包实现了用于操作字符的简单函数
func main() {
strDemo()

// 字符串倒序
s := reverse("Hello, World!")
fmt.Println(s)
}

func strDemo() {
var a, b, c string
// 根据字符串创建reader
strings.NewReader("Hello World!")

// 使用提供的多组old、new字符串对创建并返回一个*strings.Replacer
// 替换是依次进行的，匹配时不会重叠
r := strings.NewReplacer("<", "&lt;", ">", "&gt;")
fmt.Println(r.Replace("This is <b>HTML</b>!"))

// 比较a和b, 返回 0: a等于b, 1: a大于b, -1: a小于b
strings.Compare(a, b)

// 判断a与b是否相同(将unicode大写、小写、标题三种格式字符视为相同)
strings.EqualFold(a, b)

// 判断a是否以b开头，当b为空时true
strings.HasPrefix(a, b)

//

// 如果a以b结尾，则返回a去掉b结尾部分的新string。如果不是，返回a
strings.TrimSuffix(a, b)

// 如果a以b开头，则返回a去掉b开头部分的新string。如果不是，返回a
strings.TrimPrefix(a, b)

// 去除开头结尾所有的 空格换行回车缩进
strings.TrimSpace(a)

// 去除开头结尾所有的 指定字符串中的任意字符
strings.Trim(a, " ")

// 按自定义方法 去除开头结尾所有指定内容
strings.TrimFunc(a, unicode.IsLetter)

// 去除开头所有的 指定字符串中的任意字符
strings.TrimLeft(a, "0123456789")

// 按自定义方法 去除开头所有指定内容
strings.TrimLeftFunc(a, unicode.IsLetter)

// 去除结尾所有的 指定字符串中的任意字符
strings.TrimRight(a, "0123456789")

// 按自定义方法 去除结尾所有指定内容
strings.TrimRightFunc(a, unicode.IsLetter)

// 以一个或者多个空格分割成切片
strings.Fields("  foo bar  baz   ")

// 根据指定方法分割成切片
strings.FieldsFunc("  foo1;bar2,baz3...", func(c rune) bool {
return !unicode.IsLetter(c) && !unicode.IsNumber(c) // 以 不是字符或者数字 进行分割
})

// 判断a是否包含b
strings.Contains(a, b)

// 判断是否包含字符串中任意字符，只要包含字符串中一个及以上字符返回true，否则false
strings.ContainsAny("I like seafood.", "fÄo!")

// 判断是否包含rune字符
strings.ContainsRune("I like seafood.", 'f')

// 统计a中包含所有b的个数，如果b为空则返回a的长度
strings.Count(a, b)

// 检索b在a中第一次出现的位置，未检索到返回-1
strings.Index(a, b)

// 检索字符c在s中第一次出现的位置，不存在则返回-1
strings.IndexByte(a, byte('k'))

// 自定义方法检索首个字符的位置，未检索到返回-1
strings.IndexFunc("Hello, 世界", func(c rune) bool {
return unicode.Is(unicode.Han, c) // 是否包含中文字符
})

// 检索a中首个 字符串中任意字符 的位置，未检索到返回-1
strings.IndexAny(a, "abc")

// 检索a中首个 rune类型字符 的位置，未检索到返回-1
strings.IndexRune("chicken", 'k')

// 检索a中最后个b的位置，未检索到返回-1
strings.LastIndex(a, b)

// 检索a中最后个 byte类型字符 的位置，未检索到返回-1
strings.LastIndexByte(a, byte('k'))

// 自定义方法检索最后个字符的位置，未检索到返回-1
strings.LastIndexFunc(a, unicode.IsLetter)

// 将string数组以指定字符连接成一个新的string
s := []string{a, b}
strings.Join(s, ",")

// 返回count个s串联的字符串
// 例如：a = "abc"，返回 "abcabc"
strings.Repeat(a, 2)

// 返回一个 将a中的b替换为c 的新string，n为替换个数，-1替换所有
strings.Replace(a, b, c, -1)

// 返回一个 将a中的b替换为c 的新string
strings.ReplaceAll(a, b, c)

// 将a以指定字符分割成string数组
strings a, b)

// 将a以指定字符分割成string数组, n为分割个数，-1分割所有
strings.SplitN(a, b, 2)

// 将a以指定字符分割成string数组，保留b。
strings.SplitAfter(a, b)

// 将a以指定字符分割成string数组，保留b。n为分割个数，-1分割所有
strings.SplitAfterN(a, b, 2)

// 返回一个 以空格为界限，所有首个字母大写 的标题格式
strings.Title(a)

// 返回一个 所有字母大写 的标题格式
strings.ToTitle(a)

// 使用指定的映射表将 a 中的所有字符修改为标题格式返回。
strings.ToTitleSpecial(unicode.SpecialCase{}, a)

// 所有字母大写
strings.ToUpper(a)

// 使用指定的映射表将 a 中的所有字符修改为大写格式返回。
strings.ToUpperSpecial(unicode.SpecialCase{}, a)

// 所有字母小写
strings.ToLower(a)

// 使用指定的映射表将 a 中的所有字符修改为小写格式返回。
strings.ToLowerSpecial(unicode.SpecialCase{}, a)

// 遍历a按指定的rune方法处理每个字符
strings.Map(func(r rune) rune {
if r >= 'A' && r <= 'Z' {

return r

} else {

return 'a'

}
}, a)
}

func reverse(s string) string {
r := []rune(s)
for i, j := 0, len(r)-1; i < len(r)/2; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
######################################################################################
D:\go\go\go标准库示例\sync\sync-atomic.go

package main
import (
"fmt"
"math/rand"
"sync/atomic"
"time"
)

// atomic包提供了底层的原子级内存操作，对于同步算法的实现很有用
// 这些函数必须谨慎地保证正确使用。除了某些特殊的底层应用，使用通道或者sync包的函数/类型实现同步更好
// 应通过通信来共享内存，而不通过共享内存实现通信
func main() {
// 自定义value
exampleValue()

// 类型示例
example()
}

func exampleValue() {
cfg := make(map[string]int)
// 根基当前时间的unix值初始化rand状态
rand.Seed(time.Now().Unix())

// 随机生成500以内的随机数
cfg["test"] = rand.Intn(500)

// 声明atomic.Value
// 提供了一个自动加载和一个一致的类型值的存储。Value 的零值从 Load 返回 nil 。一旦 Store 被调用，Value 不能被复制
// 首次使用后不得复制 Value
var config atomic.Value

// 将 Value 的值设置为 x
// 对于给定值的所有对Store的调用都必须使用相同具体类型的值。存储不一致的类型 会panic，就像 Store（nil） 一样
config.Store(cfg)

// 返回最近的存储设置的值。如果此值没有存储调用，则返回 nil
c := config.Load()
fmt.Println(c)
}

func example() {
var i32 int32

// 更新 int32类型 内存值
atomic.StoreInt32(&i32, 15)

// 获取 int32类型 内存值
fmt.Println(atomic.LoadInt32(&i32))

// 将值添加到int32内存中（值+内存值）
fmt.Println(atomic.AddInt32(&i32, 12))
}
######################################################################################
D:\go\go\go标准库示例\sync\sync.go

package main
import (
"fmt"
"sync"
)

// sync包提供了基本的同步基元，如互斥锁
// 除了Once和WaitGroup类型，大部分都是适用于低水平程序线程，高水平的同步使用channel通信更好一些
// 本包的类型的值不应被拷贝
func main() {
// 协程同步
exampleWaitGroup()

// 协程中只调用单次方法
exampleOnce()

// 利用互斥锁进行线程操作
exampleCond()

// 资源池
examplePool()

// 并发读写互斥锁
exampleRWMutex()

// 并发map
exampleMap()
}

func exampleWaitGroup() {
// 声明sync.WaitGroup用于等待一组线程的结束
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
// 添加delta个等待线程
// 向内部计数加上delta，delta可以是负数；如果内部计数器变为0，Wait方法阻塞等待的所有线程都会释放，如果计数器小于0，方法panic
// 注意Add加上正数的调用应在Wait之前，否则Wait可能只会等待很少的线程。一般来说本方法应在创建新的线程或者其他应等待的事件之前调用
wg.Add(1)
go func(i int) {
fmt.Println(i)
// 减少WaitGroup计数器的值，应在线程的最后执行
wg.Done()
}(i)
}

// 阻塞直到WaitGroup计数器减为0
wg.Wait()
fmt.Println("finish")
}

func exampleOnce() {
// 声明sync.Once只执行一次动作的对象
var once sync.Once

// 声明一个bool值的channel
done := make(chan bool)
for i := 0; i < 10; i++ {
go func() {
// 当且仅当第一次被调用时才执行函数f
// 如果once.Do(f)被多次调用，只有第一次调用会执行f，即使f每次调用Do 提供的f值不同。需要给每个要执行仅一次的函数都建立一个Once类型的实例
// Do用于必须刚好运行一次的初始化。因为f是没有参数的，因此可能需要使用闭包来提供给Do方法调用
once.Do(func() {
fmt.Println("Only once")
})
done <- true
}()
}
for i := 0; i < 10; i++ {
<-done
}
}

func exampleCond() {
// 初始化一个互斥锁
// 可以创建为其他结构体的字段，零值为解锁状态
// Mutex类型的锁和线程无关，可以由不同的线程加锁和解锁
var locker = new(sync.Mutex)

// 使用锁locker创建一个*sync.Cond
// Cond实现了一个条件变量，一个线程集合地，供线程等待或者宣布某事件的发生
c := sync.NewCond(locker)

// 锁定
c.L.Lock()

// 唤醒所有等待c的线程。调用者在调用本方法时，建议（但并非必须）保持c.L的锁定
c.Broadcast()

// 唤醒等待c的一个线程（如果存在）。调用者在调用本方法时，建议（但并非必须）保持c.L的锁定
c.Signal()

// 解锁
c.L.Unlock()

// 自行解锁c.L并阻塞当前线程，在之后线程恢复执行时，Wait方法会在返回前锁定c.L
// 和其他系统不同，Wait除非被Broadcast或者Signal唤醒，不会主动返回
//c.Wait()
}

func examplePool() {
// 初始化一个可以分别存取的临时对象的集合
// Pool中保存的任何item都可能随时不做通告的释放掉。如果Pool持有该对象的唯一引用，这个item就可能被回收
// Pool可以安全的被多个线程同时使用
// Pool的目的是缓存申请但未使用的item用于之后的重用，以减轻GC的压力。也就是说，让创建高效而线程安全的空闲列表更容易。但Pool并不适用于所有空闲列表
// Pool的合理用法是用于管理一组静静的被多个独立并发线程共享并可能重用的临时item。Pool提供了让多个线程分摊内存申请消耗的方法
// 管理着短寿命对象的空闲列表不适合使用Pool，因为这种情况下内存申请消耗不能很好的分配。这时应该由这些对象自己实现空闲列表
var pool = new(sync.Pool)

// (可选)指定当get返回nil时生成值的函数。它不能与get调用同时更改
pool.New = func() interface{} {
return 5
}

// 将x放入池中
pool.Put(10)

// 从池中选择任意一个item，删除其在池中的引用计数，并提供给调用者
// Get方法也可能选择无视内存池，将其当作空的。调用者不应认为Get的返回这和传递给Put的值之间有任何关系
item := pool.Get()
fmt.Println(item)
}

func exampleRWMutex() {
// 初始化一个读写互斥锁
// 该锁可以被同时多个读取者持有或唯一个写入者持有
// RWMutex可以创建为其他结构体的字段；零值为解锁状态
// RWMutex类型的锁也和线程无关，可以由不同的线程加读取锁/写入和解读取锁/写入锁
var rw = new(sync.RWMutex)

// 将rw锁定为写入状态，禁止其他线程读取或者写入
rw.Lock()

// 解除rw的写入锁状态，如果未加写入锁会导致运行时错误
rw.Unlock()

// 将rw锁定为读取状态，禁止其他线程写入，但不禁止读取
rw.RLock()

// 解除rw的读取锁状态，如果m未加读取锁会导致运行时错误
rw.RUnlock()

// 返回一个互斥锁，通过调用rw.Rlock和rw.Runlock实现了Locker接口
rw.RLocker()
}

func exampleMap() {
// 声明并发Map
var m sync.Map

// 将键值对保存到sync.Map
m.Store("a", "Hello World!")
m.Store("b", "Hello Gopher!")
m.Store("c", "Hello zc!")

// 从sync.Map中根据键取值
fmt.Println(m.Load("c"))

// 根据键删除对应的键值对
m.Delete("c")

// 遍历所有sync.Map中的键值对
m.Range(func(k, v interface{}) bool {
fmt.Println("iterate:", k, v)
return true
})
}
######################################################################################
D:\go\go\go标准库示例\text\text-scanner.go

package main

import (
"fmt"
"strings"
"text/scanner"
)

// scanner包提供对utf-8文本的token扫描服务。它会从一个io.Reader获取utf-8文本，通过对Scan方法的重复调用获取一个个token
// 为了兼容已有的工具，NUL字符不被接受。如果第一个字符是表示utf-8编码格式的BOM标记，会自动忽略该标记
// 一般Scanner会跳过空白和Go注释，并会识别所有go语言规格的字面量。它可以定制为只识别这些字面量的一个子集，也可以识别不同的空白字符

func main() {
const src = `
// This is scanned code.
if a > 10 {
	someParsable = text
}`

// 创建一个扫描服务
s := new(scanner.Scanner)

// 初始化
s.Init(strings.NewReader(src))

// 设置扫描的文件名
s.Filename = "text-scanner"

// 从资源循环token或者unicode字符并返回它
for tok := s.Scan(); tok != scanner.EOF; tok = s.Scan() {
fmt.Println(s.Position, s.TokenText())
}
}
######################################################################################
D:\go\go\go标准库示例\text\text-tabwriter.go

package main

import (
"os"
"text/tabwriter"
)

// tabwriter包实现了写入过滤器（tabwriter.Writer），可以将输入的缩进修正为正确的对齐文本

func main() {
// 创建一个过滤器
w := new(tabwriter.Writer)

// 初始化，第一个参数指定输出目标
// minwidth 最小单元长度
// tabwidth tab字符的宽度
// padding  计算单元宽度时会额外加上它
// padchar  用于填充的ASCII字符，如果是'\t'，则Writer会假设tabwidth作为输出中tab的宽度，且单元必然左对齐
// flags    格式化控制
// 等同于 tabwriter.NewWriter(os.Stdout, 0, 8, 0, '\t', 0)
w.Init(os.Stdout, 0, 8, 0, '\t', 0)
w.Write([]byte("a\tb\tc\td\t."))
w.Write([]byte("123\t12345\t1234567\t123456789\t.\n"))

// 在最后一次调用Write后，必须调用Flush方法以清空缓存，并将格式化对齐后的文本写入生成时提供的output中
w.Flush()

// 最小单元长度为5，宽度额外增加1，空格填充，右对齐
w.Init(os.Stdout, 5, 0, 1, ' ', tabwriter.AlignRight)
w.Write([]byte("a\tb\tc\td\t."))
w.Write([]byte("123\t12345\t1234567\t123456789\t.\n"))
w.Flush()
}
######################################################################################
D:\go\go\go标准库示例\text\text-template.go

package main

import (
"bytes"
"fmt"
"log"
"os"
"strings"
"text/template"
)

// template包实现了数据驱动的用于生成文本输出的模板
// 如果要生成HTML格式的输出，参见html/template包，该包提供了和本包相同的接口，但会自动将输出转化为安全的HTML格式输出，可以抵抗一些网络攻击。
// 通过将模板应用于一个数据结构（即该数据结构作为模板的参数）来执行，来获得输出。
//模板中的注释引用数据接口的元素（一般如结构体的字段或者字典的键）来控制执行过程和获取需要呈现的值。
//模板执行时会遍历结构并将指针表示为'.'（称之为"dot"）指向运行过程中数据结构的当前位置的值。
// 用作模板的输入文本必须是utf-8编码的文本。"Action"—数据运算和控制单位—由"{{"和"}}"界定；
//在Action之外的所有文本都不做修改的拷贝到输出中。Action内部不能有换行，但注释可以有换行。
// 经解析生成模板后，一个模板可以安全的并发执行

func main() {
// 基础
example()

// 设置action分界字符串
exampleDelims()

// 自动解析
exampleAuto()
}

func example() {
// 声明buffer
var buf bytes.Buffer
var jsBuf bytes.Buffer

// 声明内容
var data = []byte("<div>Hello World!</div>")
var p = []byte("<p>test</p>")
var jsData = []byte("<script>alert('Hello World!')</script>")
var url = []byte("http://www.baidu.com/test?a=1&b=2")

// 向w中写入b的HTML转义等价表示
template.HTMLEscape(&buf, data)
fmt.Println(string(buf.Bytes()))

// 返回s的HTML转义等价表示字符串
str := template.HTMLEscapeString(string(data))
fmt.Println(str)

// 返回其所有参数文本表示的HTML转义等价表示字符串
strs := template.HTMLEscaper(string(data), string(p))
fmt.Println(string(strs))

// 向w中写入b的JavaScript转义等价表示
template.JSEscape(&jsBuf, jsData)
fmt.Println(string(jsBuf.Bytes()))

// 返回s的JavaScript转义等价表示字符串
jsStr := template.JSEscapeString(string(jsData))
fmt.Println(jsStr)

// 返回其所有参数文本表示的JavaScript转义等价表示字符串
jsStrs := template.JSEscaper(string(jsData), string(p))
fmt.Println(jsStrs)

// 返回其所有参数文本表示的可以嵌入URL查询的转义等价表示字符串
urlStr := template.URLQueryEscaper(string(url))
fmt.Println(urlStr)

var testBuf bytes.Buffer

var (
test    = `Names:{{block "list" .}}{{"\n"}}{{range .}}{{println "-" .}}{{end}}{{end}}`
overlay = `{{define "list"}} {{join . ", "}}{{end}} `
)
// 声明数据集
var dataMap = []string{"张三", "李四", "王五", "赵六", "黑七"}

// 定义了函数名字符串到函数的映射，每个函数都必须有1到2个返回值，如果有2个则后一个必须是error接口类型；如果有2个返回值的方法返回的error非nil，模板执行会中断并返回给调用者该错误
var funcs = template.FuncMap{"join": strings.Join}

// 创建一个名为name的模板
t := template.New("test")

// 返回模板t的名字
t.Name()

// 向模板t的函数字典里加入参数funcMap内的键值对。如果funcMap某个键值对的值不是函数类型或者返回值不符合要求会panic
// 但是，可以对t函数列表的成员进行重写。方法返回t以便进行链式调用
t.Funcs(funcs)

// 返回模板的一个副本，包括所有相关联的模板
// 模板的底层表示树并未拷贝，而是拷贝了命名空间，因此拷贝调用Parse方法不会修改原模板的命名空间
// Clone方法用于准备模板的公用部分，向拷贝中加入其他关联模板后再进行使用
t.Clone()

// 创建一个和t关联的名字为name的模板并返回它。这种可以传递的关联允许一个模板使用template action调用另一个模板
t.New("hello")

// 返回与t相关联的模板的切片，包括t自己
t.Templates()


// 将字符串text解析为模板。嵌套定义的模板会关联到最顶层的t
// Parse可以多次调用，但只有第一次调用可以包含空格、注释和模板定义之外的文本
// 如果后面的调用在解析后仍剩余文本会引发错误、返回nil且丢弃剩余文本；如果解析得到的模板已有相关联的同名模板，会覆盖掉原模板
out, _ := t.Parse(test)

// 解析filenames指定的文件里的模板定义并将解析结果与t关联。如果发生错误，会停止解析并返回nil，否则返回(t, nil)。至少要提供一个文件
t.ParseFiles("testdata/htmlTemplateTest.html")

// 解析匹配pattern的文件里的模板定义并将解析结果与t关联。如果发生错误，会停止解析并返回nil，否则返回(t, nil)。至少要存在一个匹配的文件
t.ParseGlob("testdata/htmlTemplate/*.html")

// 用于包装返回(*Template, error)的函数/方法调用，它会在err非nil时panic，一般用于变量初始化
mt := template.Must(out.Clone())

// 将解析好的模板应用到data上，并将输出写入wr
// 如果执行时出现错误，会停止执行，但有可能已经写入wr部分数据。模板可以安全的并发执行
_ = out.Execute(&testBuf, dataMap)
fmt.Println(testBuf.String())
mOut, _ := mt.Parse(overlay)
_ = mOut.Execute(&testBuf, dataMap)
fmt.Println(testBuf.String())
}

func exampleDelims() {
var buf bytes.Buffer
var text = "<<.Greeting>> {{.Name}}"

data := struct {
Greeting string
Name     string
}{
Greeting: "Hello",
Name:     "Joe",
}

// 创建模板
t := template.New("tpl")

// 用于设置action的分界字符串，应用于之后的Parse、ParseFiles、ParseGlob方法
// 嵌套模板定义会继承这种分界符设置。空字符串分界符表示相应的默认分界符：{{或}}。返回值就是t，以便进行链式调用
t = t.Delims("<<", ">>")
t = template.Must(t.Parse(text))

if err := t.Execute(&buf, data); err != nil {
log.Fatal(err)
}
fmt.Println(buf.String())
}

func exampleAuto() {
var (
text = `{{define "T"}}Hello, {{.}}!{{end}}`
data = "<script>alert('you have been pwned')</script>\n"
)
t, err := template.New("test").Parse(text)
if err != nil {
log.Fatal(err)
}

// 类似Execute，但是使用名为name的t关联的模板产生输出
if err := t.ExecuteTemplate(os.Stdout, "T", data); err != nil {
log.Fatal(err)
}
}
######################################################################################
D:\go\go\go标准库示例\time\time.go


package main

import (
"fmt"
"time"
)

// time包提供了时间的显示和测量用的函数。日历的计算采用的是公历
func main() {
// 返回当前本地时间 2020-03-25 14:18:04.9212793 +0800 CST m=+2.003796801
time.Now()

// 创建一个本地时间，对应sec和nsec表示的Unix时间（从January 1, 1970 UTC至该时间的秒数和纳秒数）
time.Unix(1e9, 0)

// 返回使用给定的名字创建的*time.Location
// 如果name是""或"UTC"，返回UTC；如果name是"Local"，返回Local；否则name应该是IANA时区数据库里有记录的地点名（该数据库记录了地点和对应的时区），如"America/New_York"
// 需要的时区数据库可能不是所有系统都提供，特别是非Unix系统。此时LoadLocation会查找环境变量ZONEINFO指定目录或解压该变量指定的zip文件（如果有该环境变量）；然后查找Unix系统的惯例时区数据安装位置，最后查找$GOROOT/lib/time/zoneinfo.zip
loc, _ := time.LoadLocation("Europe/Berlin")

// 使用给定的地点名name和时间偏移量offset（单位秒）创建并返回一个Location
time.FixedZone("Beijing Time", int((8 * time.Hour).Seconds()))

// 返回指定时间
t := time.Date(2019, time.February, 7, 0, 0, 0, 0, time.UTC)

// 返回t的地点和时区信息
t.Location()

// 返回采用本地和本地时区，但指向同一时间点的Time
t.Local()

// 返回unix时间，即从时间点January 1, 1970 UTC到时间点t所经过的时间（单位秒）
t.Unix()

// 返回采用UTC和零时区，但指向同一时间点的Time
t.UTC()

// 计算t所在的时区，返回该时区的规范名（如"CET"）和该时区相对于UTC的时间偏移量（单位秒）
t.Zone()

// 报告t是否代表Time零值的时间点，January 1, year 1, 00:00:00 UTC
t.IsZero()

// 返回采用loc指定的地点和时区，但指向同一时间点的Time。如果loc为nil会panic
t.In(loc)

// 将t表示为Unix时间，即从时间点January 1, 1970 UTC到时间点t所经过的时间（单位纳秒）
// 如果纳秒为单位的unix时间超出了int64能表示的范围，结果是未定义的。注意这就意味着Time零值调用UnixNano方法的话，结果是未定义的
t.UnixNano()

// 判断两个时间是否相同，会考虑时区的影响，因此不同时区标准的时间也可以正确比较。本方法和用t==u不同，这种方法还会比较地点和时区信息
t.Equal(time.Now())

// 判断t的时间点是否在u之前
t.Before(time.Now())

// 判断t的时间点是否在u之后
t.After(time.Now())

// 返回时间点t对应的年、月、日
t.Date()

// 返回t对应的那一天的时、分、秒
t.Clock()

// 返回时间点t对应的年份
t.Year()

// 返回时间点t对应的那一年的第几天，平年的返回值范围[1,365]，闰年[1,366]
t.YearDay()

// 返回时间点t对应那一年的第几月
t.Month()

// 返回时间点t对应那一月的第几日
t.Day()

// 返回时间点t对应的那一周的周几
t.Weekday()

// 返回时间点t对应的ISO 9601标准下的年份和星期编号
// 星期编号范围[1,53]，1月1号到1月3号可能属于上一年的最后一周，12月29号到12月31号可能属于下一年的第一周
t.ISOWeek()

// 返回t对应的那一天的第几小时，范围[0, 23]
t.Hour()

// 返回t对应的那一小时的第几分种，范围[0, 59]
t.Minute()

// 返回t对应的那一分钟的第几秒，范围[0, 59]
t.Second()

// 返回t对应的那一秒内的纳秒偏移量，范围[0, 999999999]
t.Nanosecond()

// 增加2小时, 减少使用负号
t.Add(time.Hour * 2)

// 返回增加了给出的年份、月份和天数的时间点Time。例如，时间点January 1, 2011调用AddDate(-1, 2, 3)会返回March 4, 2010
t.AddDate(1, 2, 3)

// 获取当前时间减去指定时间的时间
// 如果结果超出了Duration可以表示的最大值/最小值，将返回最大值/最小值。要获取时间点t-d（d为Duration），可以使用t.Add(-d)
t.Sub(time.Now())

// 返回距离t最近的时间点，该时间点应该满足从Time零值到该时间点的时间段能整除d；如果有两个满足要求的时间点，距离t相同，会向上舍入；如果d <= 0，会返回t的拷贝
t.Round(time.Hour)

// 类似Round，但是返回的是最接近但早于t的时间点；如果d <= 0，会返回t的拷贝
t.Truncate(time.Hour)

// 根据layout指定的格式返回t代表的时间点的格式化文本表示
t.Format("2006-01-02 15:04:05")

// 返回采用如下格式字符串的格式化时间
// "2006-01-02 15:04:05.999999999 -0700 MST"
t.String()

// 实现了gob.GobEncoder接口
gobBytes, _ := t.GobEncode()

// 实现了gob.GobDecoder接口
_ = t.GobDecode(gobBytes)

// 实现了encoding.BinaryMarshaler接口
binaryBytes, _ := t.MarshalBinary()

// 实现了encoding.BinaryUnmarshaler接口
_ = t.UnmarshalBinary(binaryBytes)

// 实现了json.Marshaler接口
jsonBytes, _ := t.MarshalJSON()

// 实现了json.Unmarshaler接口
_ = t.UnmarshalJSON(jsonBytes)

// 实现了encoding.TextMarshaler接口
textBytes, _ := t.MarshalText()

// 实现了encoding.TextUnmarshaler接口
_ = t.UnmarshalText(textBytes)

// 解析一个格式化的时间字符串并返回它代表的时间
// layout规定了参考格式
time.Parse("2006 Jan 02 15:04:05", "2019 Feb 07 12:15:30.918273645")

// 类似Parse但有两个重要的不同之处
// 第一，当缺少时区信息时，Parse将时间解释为UTC时间，而ParseInLocation将返回值的Location设置为loc
// 第二，当时间字符串提供了时区偏移量信息时，Parse会尝试去匹配本地时区，而ParseInLocation会去匹配loc
time.ParseInLocation("2006 Jan 02 15:04:05", "2019 Feb 07 12:15:30.918273645", loc)

// 解析一个时间段字符串
// 一个时间段字符串是一个序列，每个片段包含可选的正负号、十进制数、可选的小数部分和单位后缀，如"300ms"、"-1.5h"、"2h45m"
// 合法的单位有"ns"、"us" /"µs"、"ms"、"s"、"m"、"h"
d, _ := time.ParseDuration("1h15m30.918273645s")
fmt.Println(d.Hours(), d.Minutes(), d.Nanoseconds())

// 返回从t到现在经过的时间，等价于time.Now().Sub(t)
time.Since(t)

// 阻塞当前go程至少d代表的时间段。d<=0时，Sleep会立刻返回
time.Sleep(time.Second * 2)

// 创建一个Timer，它会在最少过去时间段d后到期，向其自身的C字段发送当时的时间
time.NewTimer(time.Minute * 2)

// 会在另一线程经过时间段d后向返回值发送当时的时间。等价于NewTimer(d).C
time.After(time.Minute * 2)

// 另起一个go程等待时间段d过去，然后调用f。它返回一个Timer，可以通过调用其Stop方法来取消等待和对f的调用
time.AfterFunc(time.Millisecond*1000, func() {
fmt.Println("time after 1 second test")
})

// 返回一个新的Ticker，该Ticker包含一个通道字段，并会每隔时间段d就向该通道发送当时的时间
// 它会调整时间间隔或者丢弃tick信息以适应反应慢的接收者
// 如果d<=0会panic。关闭该Ticker可以释放相关资源
time.NewTicker(time.Second * 10)

// 是NewTicker的封装，只提供对Ticker的通道的访问。如果不需要关闭Ticker，本函数就很方便
time.Tick(time.Second * 10)
}
######################################################################################
D:\go\go\go标准库示例\unicode\unicode-utf16.go

package main
import "unicode/utf16"

// utf16包实现了UTF-16序列的编解码
func main() {
var b = []rune("Hello World!")

// 判断r是否可以编码为一个utf16的代理对
utf16.IsSurrogate('H')

// 将unicode码值序列编码为utf-16序列
e := utf16.Encode(b)

// 将utf-16序列解码为unicode码值序列
utf16.Decode(e)

// 将unicode码值r编码为一个utf-16的代理对。如果不能编码，会返回(U+FFFD, U+FFFD)
r1, r2 := utf16.EncodeRune('H')

// 将utf-16代理对(r1, r2)解码为unicode码值。如果代理对不合法，会返回U+FFFD
utf16.DecodeRune(r1, r2)
}
######################################################################################
D:\go\go\go标准库示例\unicode\unicode-utf8.go

package main
import (
"unicode/utf8"
)

// utf8包实现了对utf-8文本的常用函数和常数的支持，包括rune和utf-8编码byte序列之间互相翻译的函数
func main() {
var b = []byte("Hello World!")

// 判断切片p是否包含完整且合法的utf-8编码序列
utf8.Valid(b)

// 判断r是否可以编码为合法的utf-8序列
utf8.ValidRune('H')

// 判断s是否包含完整且合法的utf-8编码序列
utf8.ValidString(string(b))

// 将r的utf-8编码序列写入p（p必须有足够的长度），并返回写入的字节数
utf8.EncodeRune(b, 'H')

// 解码p开始位置的第一个utf-8编码的码值，返回该码值和编码的字节数
// 如果编码不合法，会返回(RuneError, 1)。该返回值在正确的utf-8编码情况下是不可能返回的
utf8.DecodeRune(b)

// 类似DecodeRune但输入参数是字符串
utf8.DecodeRuneInString(string(b))

// 解码p中最后一个utf-8编码序列，返回该码值和编码序列的长度
utf8.DecodeLastRune(b)

// 类似DecodeLastRune但输入参数是字符串
utf8.DecodeLastRuneInString(string(b))

// 判断切片p是否以一个码值的完整utf-8编码开始
// 不合法的编码因为会被转换为宽度1的错误码值而被视为完整的
// 如中文字符占3位byte，一位byte判断为false，完整的3位为true
utf8.FullRune(b)

// 类似FullRune但输入参数是字符串
utf8.FullRuneInString(string(b))

// 返回p中的utf-8编码的码值的个数。错误或者不完整的编码会被视为宽度1字节的单个码值
utf8.RuneCount(b)

// 类似RuneCount但输入参数是一个字符串
utf8.RuneCountInString(string(b))

// 返回r编码后的字节数。如果r不是一个合法的可编码为utf-8序列的值，会返回-1
utf8.RuneLen('世')

// 判断字节b是否可以作为某个rune编码后的第一个字节。第二个即之后的字节总是将左端两个字位设为10
utf8.RuneStart('世')
}
######################################################################################
D:\go\go\go标准库示例\unicode\unicode.go

package main
import (
"fmt"
"unicode"
)

// unicode包提供数据和函数来测试Unicode代码点的一些属性
func main() {
// 判断示例
exampleIs()

// 对应示例
exampleSimpleFold()

// 转换示例
exampleTo()
}

func exampleIs() {
// constant with mixed type runes
const mixed = "\b5Ὂg̀9! ℃ᾭG"
for _, c := range mixed {
fmt.Printf("For %q:\n", c)

// 判断一个字符是否是控制字符，主要是策略C的字符和一些其他的字符如代理字符
if unicode.IsControl(c) {
fmt.Println("\tis control rune")
}

// 判断一个r字符是否是十进制数字字符
if unicode.IsDigit(c) {
fmt.Println("\tis digit rune")
}

// 判断一个字符是否是unicode图形。包括字母、标记、数字、符号、标点、空白，参见L、M、N、P、S、Zs
if unicode.IsGraphic(c) {
fmt.Println("\tis graphic rune")
}

// 判断一个字符是否是字母
if unicode.IsLetter(c) {
fmt.Println("\tis letter rune")
}

// 判断字符是否是小写字母
if unicode.IsLower(c) {
fmt.Println("\tis lower case rune")
}

// 判断字符是否是大写字母
if unicode.IsUpper(c) {
fmt.Println("\tis upper case rune")
}

// 判断一个字符是否是标记字符
if unicode.IsMark(c) {
fmt.Println("\tis mark rune")
}

// 判断一个字符是否是数字字符
if unicode.IsNumber(c) {
fmt.Println("\tis number rune")
}

// 判断一个字符是否是go的可打印字符
// 本函数基本和IsGraphic一致，只是ASCII空白字符U+0020会返回假
if unicode.IsPrint(c) {
fmt.Println("\tis printable rune")
}

// 判断一个字符是否是unicode标点字符
if unicode.IsPunct(c) {
fmt.Println("\tis punct rune")
}

// 判断一个字符是否是空白字符
// 在Latin-1字符空间中，空白字符为：'\t', '\n', '\v', '\f', '\r', ' ', U+0085 (NEL), U+00A0 (NBSP).其它的空白字符请参见策略Z和属性Pattern_White_Space
if unicode.IsSpace(c) {
fmt.Println("\tis space rune")
}

// 判断一个字符是否是unicode符号字符
if unicode.IsSymbol(c) {
fmt.Println("\tis symbol rune")
}

// 判断字符是否是标题字母
if unicode.IsTitle(c) {
fmt.Println("\tis title case rune")
}
}
}

func exampleSimpleFold() {
// 迭代在unicode标准字符映射中互相对应的unicode码值
// 在与r对应的码值中（包括r自身），会返回最小的那个大于r的字符（如果有）；否则返回映射中最小的字符
fmt.Printf("%#U\n", unicode.SimpleFold('A'))      // 'a'
fmt.Printf("%#U\n", unicode.SimpleFold('a'))      // 'A'
fmt.Printf("%#U\n", unicode.SimpleFold('K'))      // 'k'
fmt.Printf("%#U\n", unicode.SimpleFold('k'))      // '\u212A' (Kelvin symbol, K)
fmt.Printf("%#U\n", unicode.SimpleFold('\u212A')) // 'K'
fmt.Printf("%#U\n", unicode.SimpleFold('1'))      // '1'
}

func exampleTo() {
const lcG = 'g'

// 转大写
fmt.Printf("%#U\n", unicode.To(unicode.UpperCase, lcG))
fmt.Println(unicode.ToUpper(lcG))

// 转小写
fmt.Printf("%#U\n", unicode.To(unicode.LowerCase, lcG))
fmt.Println(unicode.ToLower(lcG))

// 转标题
fmt.Printf("%#U\n", unicode.To(unicode.TitleCase, lcG))
fmt.Println(unicode.ToTitle(lcG))
}
#################################
D:\go\go\go标准库示例\unsafe\unsafe.go
package main
import (
"fmt"
"unsafe"
)

// unsafe包提供了一些跳过go语言类型安全限制的操作
func main() {
var hello = Hello{}

// 返回类型v本身数据所占用的字节数
// 返回值是“顶层”的数据占有的字节数
// 例如，若v是一个切片，它会返回该切片描述符的大小，而非该切片底层引用的内存的大小
s := unsafe.Sizeof(hello)
fmt.Println(s)

// 返回类型v所代表的结构体字段在结构体中的偏移量，它必须为结构体类型的字段的形式
// 换句话说，它返回该结构起始处与该字段起始处之间的字节数
f := unsafe.Offsetof(hello.b)
fmt.Println(f)

// 返回类型v的对齐方式（即类型v在内存中占用的字节数）
// 若是结构体类型的字段的形式，它会返回字段f在该结构体中的对齐方式
a := unsafe.Alignof(hello)
fmt.Println(a)
}

type Hello struct {
a bool
b string
c int
d []float64
}